Elva Guide ## Sections • [Welcome to Elva](https://docs.getelva.ai/elva/welcome-to-elva.md): Make every API agent-ready: from any repo to a production MCP server in minutes. Elva builds a living catalog of your APIs, then keeps contracts, testing, monitoring, and changelogs running as one continuous pipeline so AI agents can actually call them. Point it at a repo or an OpenAPI spec, and it discovers your real endpoints, scores them for AI-readiness, and deploys a hosted MCP server that Claude, Cursor, VS Code, Gemini, and Codex can plug into. Catalog, contracts, MCP, testing, monitoring, changelogs, and insights live in one tool, not seven disconnected ones. Elva is a hosted platform: you work in the browser at app.getelva.ai , and the scoring engine is a public API at api.getelva.ai Start here Quickstart: repo to MCP Go from a GitHub repo or spec to an agent-callable MCP server, with the exact connect commands. How Elva works See the continuous pipeline and hosted architecture that turn ingestion into agent-ready tools. Build your catalog The living API catalog Every API in one scored, searchable place, refreshed on each scan with owners and last commit. Hosted MCP servers Turn any collection into a hosted MCP server where you pick exactly which operations become tools. Trust your contracts API contracts Compose a versioned, governed promise from your collections — field-level PII control, drift alerts, and one-click publishing included. Spec quality & scoring 30+ checks across design, developer experience, AI-readiness, and security produce a grade you can trust. Test and watch API testing Fire real requests through an SSRF-safe proxy and generate client snippets in seconds. MCP insights & logs See which agents call which tools, with latency, error rate, and token usage per server. Go further AI assistant & semantic search Chat with your catalog and search specs semantically, with tool-calling over your collections. The enterprise MCP gateway Every agent call authenticated, encrypted, and logged through a hosted gateway that never stores your credentials. • [Quickstart: repo to MCP](https://docs.getelva.ai/get-started/quickstart-repo-to-mcp.md): Make every API agent-ready: from any repo to a production MCP server in minutes. Elva builds a living catalog of your APIs, then keeps contracts, testing, monitoring, and changelogs running as one continuous pipeline so AI agents can actually call them. Point it at a repo or an OpenAPI spec, and it discovers your real endpoints, scores them for AI-readiness, and deploys a hosted MCP server that Claude, Cursor, VS Code, Gemini, and Codex can plug into. Catalog, contracts, MCP, testing, monitoring, changelogs, and insights live in one tool, not seven disconnected ones. Elva is a hosted platform: you work in the browser at app.getelva.ai , and the scoring engine is a public API at api.getelva.ai Start here Quickstart: repo to MCP Go from a GitHub repo or spec to an agent-callable MCP server, with the exact connect commands. How Elva works See the continuous pipeline and hosted architecture that turn ingestion into agent-ready tools. Build your catalog The living API catalog Every API in one scored, searchable place, refreshed on each scan with owners and last commit. Hosted MCP servers Turn any collection into a hosted MCP server where you pick exactly which operations become tools. Trust your contracts API contracts Compose a versioned, governed promise from your collections — field-level PII control, drift alerts, and one-click publishing included. Spec quality & scoring 30+ checks across design, developer experience, AI-readiness, and security produce a grade you can trust. Test and watch API testing Fire real requests through an SSRF-safe proxy and generate client snippets in seconds. MCP insights & logs See which agents call which tools, with latency, error rate, and token usage per server. Go further AI assistant & semantic search Chat with your catalog and search specs semantically, with tool-calling over your collections. The enterprise MCP gateway Every agent call authenticated, encrypted, and logged through a hosted gateway that never stores your credentials. Ship an agent-callable MCP server from an existing repo without writing a line of glue code. Sign in, point Elva at your source, and let it scan, score, and deploy a hosted MCP that Claude, Cursor, or any MCP client can call in minutes. The path from repo to agent Six moves take you from a cold start to an agent making real calls against your API. The repo scanner and the spec importer converge on the same place: a scored collection you can turn into a hosted MCP. • [How Elva works](https://docs.getelva.ai/get-started/how-elva-works.md): Elva runs your APIs through one continuous pipeline , not seven disconnected tools. Code goes in one end, and an agent-callable, monitored, scored MCP server comes out the other, with contracts, tests, and changelogs generated along the way. Catalog, contracts, MCP, testing, monitoring, changelogs and insights on one rail. The pipeline, end to end Everything starts with ingest and ends with an agent making a real call. Each stage feeds the next, and they all read from the same catalog, so nothing drifts out of sync. Built for the agentic era APIs were documented for humans reading docs pages. Agents need something stronger: interfaces they can discover, trust, and call, backed by specs that are actually current. In most companies the spec drifts from the code within weeks, the catalog is a wiki nobody updates, and every team hand-rolls its own MCP plumbing. Elva replaces all of that with one pipeline that starts from whatever you already have, a repo, a spec, a Postman workspace, or a plain-language prompt, and ends with a governed, monitored, agent-callable API surface. The pipeline, stage by stage Each stage in the diagram above earns its place. Together they turn a moving codebase into an API surface agents can rely on: Four on-ramps. Elva meets your APIs where they live. Upload a spec, paste a Postman key, connect a repo, or describe the API you want, with no SDK and no plugin to install. The living catalog. Every route lands in one source of truth that rebuilds from source on every push, instead of a wiki that quietly dies. Scoring. Each API gets graded across design, developer experience, AI-readiness, and security, so you know it is agent-ready before an agent finds out for you. MCP generation. Endpoints become typed, well-described MCP tools automatically, the plumbing every team currently builds by hand. Hosted runtime. Your MCP server goes live on Elva with zero infrastructure to run, ready for Claude, Cursor, VS Code, Gemini, and Codex. The always-on layer. Git-derived changelogs, a safe test mode, and live monitoring cover the parts everyone forgets until production. Why it never goes stale The whole system runs on a git-driven loop: push, rescan, re-score, redeploy. Because the catalog is rebuilt from your source rather than maintained by hand, it cannot rot. Line numbers stay right, owners stay attributed, the changelog writes itself, and the MCP tools your agents call tomorrow reflect the code you merged today. Start where your APIs are Elva is built by the team behind Theneo, trusted for API documentation from top startups to Fortune 500 companies. If you want to see the pipeline on your own code, the quickstart takes you from a cold repo to an agent making real calls in six moves, and it all starts at app.getelva.ai . • [Bring in your APIs](https://docs.getelva.ai/api-collections/bring-in-your-apis.md): Elva meets your APIs wherever they already live. Point it at a spec, a Postman workspace, a GitHub repo, or a blank prompt, and every route lands in the same living catalog : validated, scored, and searchable the moment it arrives. OpenAPI, Postman, GitHub, and AI all converge into one catalog. There is no plugin to install and no SDK to wire up. Sign in at app.getelva.ai , pick an on-ramp, and Elva does the parsing, conversion, and scoring for you. Four ways in Every path ends the same way: a stored spec, a computed AI-readiness score, and vector embeddings for semantic search. Choose whichever matches where your API lives today. OpenAPI Postman GitHub AI Bring an existing OpenAPI or Swagger contract, either as a file or a link. Upload a .yaml , .yml , or .json file by drag-and-drop or file picker. Import by URL and Elva fetches it server-side through a guarded proxy, so browser CORS never blocks you. Both 2.0, 3.0, and 3.1 specs are accepted. JSON is normalized to YAML the moment it hits the editor, so what you work on is always clean, readable YAML. URL imports are capped at 10MB and only accept http and https schemes. Anything larger or on another protocol is rejected before a byte is read. Already living in Postman? Paste a Postman API key and Elva pulls your collections and converts them to OpenAPI automatically. See the step-by-step flow in the next section. No spec yet? Elva reads endpoints straight from your source code across five language ecosystems, then auto-builds scored collections, an owner-attributed catalog, and a git-derived changelog. This is the deepest on-ramp. It discovers real routes in Express, FastAPI, Spring, gin, and more, with no OpenAPI file required. Inside the code scanner See exactly how Elva finds endpoints in real source across JS/TS, Python, Go, and Java. The living API catalog Learn how repo scans materialize into collections that refresh on every push. Starting from nothing? Describe the API you want in plain language and Elva generates a valid OpenAPI 3.1 spec, streaming it live into the editor as it writes. When the draft is ready, it drops straight into your catalog like any other collection, ready to score, test, and expose as an MCP server. Import from Postman Postman collections are transpiled to OpenAPI on Elva, then treated exactly like any imported spec. The conversion is handled by an automatic converter and re-validated before anything is saved. 1 Paste your Postman API key Generate a key from your Postman account settings, then paste it into the connect screen. Elva uses it only to list and read the collections you choose. 2 Select up to 20 collections Search and check the collections you want. You can import as many as 20 collections per run; select-all respects that ceiling. 3 Elva converts and scores each one Every collection is transpiled to OpenAPI, validated, stored, quality-scored, and embedded for search. You get a per-collection report of what imported and what failed. If a collection cannot be converted to a valid OpenAPI document, that single import fails with a clear reason while the rest continue. Nothing partial is silently saved. What happens on every import OpenAPI or Swagger file Drag in .yaml , .yml , or .json , any version from 2.0 to 3.1. JSON is normalized to clean YAML the moment it lands in the editor. OpenAPI by URL Point Elva at any http or https link and it fetches server-side through a guarded proxy. 10MB cap, and browser CORS never gets in the way. Validated with Elva’s OpenAPI parser, so broken specs are caught immediately. Stored with a SHA-256 content hash, so the spec is only re-uploaded when it actually changes. Quality-scored across design, developer experience, AI-readiness, and security. Embedded in the background so the AI assistant can search it semantically. Supported sources at a glance Source Format How it arrives Limtes OpenAPI / Swagger file .yaml , .yml , .json (2.0 / 3.0 / 3.1) Drag-and-drop or file picker JSON normalized to YAML in the editor OpenAPI by URL YAML or JSON at any http / https link Fetched server-side via a guarded proxy 10MB cap, http / https only Postman Postman collections Paste an API key, converted to OpenAPI Up to 20 collections per import GitHub repo Source code (JS/TS, Python, Go, Java/Kotlin) + specs OAuth connect and scan See the code scanner AI from scratch Plain-language prompt Generated as OpenAPI 3.1 Streamed into the editor Specs are processed on Elva to parse, score, and index them. Keep real secrets, tokens, and live credentials out of the specs you import: use placeholder values in examples and auth fields instead. Where to go next The living API catalog See how imported specs become collections that stay current and searchable. Spec quality & scoring Understand the grades Elva assigns the instant your API lands. • [Inside the code scanner](https://docs.getelva.ai/api-collections/inside-the-code-scanner.md): Point Elva at a repo and it reads your source the way a senior engineer would: it finds the frameworks, follows the routers, and pulls out every real endpoint across five language ecosystems. No annotations to add, no config to write, no code to run. One scan, three layers of discovery, every endpoint scored by confidence. The scanner is the muscle behind the living catalog. This page opens it up so you can judge the depth before you connect a single repo. Static parse only. Elva reads your code with an AST parser and pattern matchers. It never executes your code, never installs your dependencies, and never runs your tests. The clone is shallow, lands in a temp directory, and is deleted the moment the scan finishes. Three layers of discovery Elva does not rely on a single trick. It runs three passes over the clone and keeps the strongest signal for every route, so a repo with a hand-written spec, framework routes, and undocumented handlers all end up in one catalog. 1. OpenAPI and Swagger specs. If your repo already ships a contract ( openapi.yaml , swagger.json , api-docs , and friends), Elva parses it directly. These endpoints carry a discovery confidence of 1.0 , because the spec is the source of truth. The raw spec files are archived too, so insights and MCP generation can use the original contract. 2. Static analysis of framework routes. Elva walks your actual source with a real parser (ts-morph for JS/TS) and resolves routes the way the framework does at runtime, including mounted-router prefixes. Confidence lands between 0.55 and 0.95 depending on how unambiguous the route is. 3. AI fallback extraction. When AI scanning is enabled, Elva sends routing-looking files that the first two passes missed to an LLM, which extracts endpoints at confidence 0.5 . This catches custom routers and exotic patterns the static analyzers do not know. Endpoints are deduplicated by service | method | path , and the highest-confidence discovery wins . A route found in both your spec and your code is counted once, at confidence 1.0. Language and framework coverage Static analysis is tuned per framework. Each detector knows the idioms of its ecosystem, from Express route chaining to Spring’s class-level @RequestMapping base paths. Title Description Title Ecosystem Frameworks detected Discovery confidence JavaScript / TypeScript Express, Fastify, NestJS, Koa, Hono NestJS 0.95 ; direct routes 0.85 ; route chains 0.7 ; all / use → ANY 0.6 ; regex fallback 0.6 Python FastAPI, Flask, Django FastAPI decorators 0.8 ; Flask @route 0.75 ; Flask default GET 0.6 ; Django path() / re_path() → ANY 0.55 Go gin, echo, chi, net/http Router calls 0.75 ; http.HandleFunc → ANY 0.55 Java / Kotlin Spring MVC Method annotations ( @GetMapping etc.) 0.7 ; generic @RequestMapping(method=…) 0.6 Any (spec) OpenAPI 3.x, Swagger 2.0 1.0 Any (AI) LLM fallback on routing files 0.5 The JS/TS analyzer resolves mounted prefixes across files, so app.use('/api/v1', userRouter) plus userRouter.get('/profile') correctly produces /api/v1/profile . Local mounts override file-level mounts, and template-literal routes keep their shape by swapping ${...} for {param} . What each service becomes Before scanning routes, Elva splits your repo into services by detecting manifest files. A monorepo with a Node gateway, a Go worker, and a Python service is scanned as three distinct services, each with its own language and framework. Title Description Manifest Detected as package.json Node service (express / fastify / nestjs / koa / hono) go.mod Go service (gin / echo / chi) pom.xml , build.gradle Java or Kotlin service (Spring) pyproject.toml , requirements.txt Python service (fastapi / flask / django) Dockerfile Container service openapi.yaml / swagger.json Spec-only service Nested workspace roots are collapsed so an aggregator package.json at the repo root does not shadow real sub-services. The scan pipeline A scan job moves through named stages, and the progress bar you see in the app maps directly to them. Every stage writes to the ScanJob record so you can watch it live. • [The living API catalog](https://docs.getelva.ai/api-collections/the-living-api-catalog.md): Every scan turns your repo into a living catalog : scored, searchable collections that rebuild themselves on every push so what agents see is always what you shipped. What a collection is A collection is one API spec, plus everything Elva computes around it. Under the hood each collection carries: The stored spec (synthesized OpenAPI from a repo scan, or the file you imported), re-uploaded to storage only when its content hash changes. Computed insights — the overall score and A to F grade, per-category breakdowns, and error/warning counts. Embeddings of every operation, schema, and parameter so the AI assistant and semantic search can retrieve it. That means a collection is never a static file dump. It is a scored, indexed, agent-queryable unit of your API surface. How the catalog organizes itself When Elva scans a repo, it does not drop one giant spec on you. It derives buckets and materializes each one as a collection, so your catalog mirrors how your system is actually built. Title Description Repo shape What Elva does No services detected Collapses to a single All endpoints collection (only if endpoints exist) Normal service One collection per service Large service Splits into per-domain collections when it has 50+ endpoints across 3+ domains, keeping a Misc bucket so nothing is lost Same domain in several services Merges into one repo-wide collection (for example, Users across core and frontend) EP[Endpoints and services]; EP-->Buckets[Derive buckets]; Buckets-->Svc[Per service]; Buckets-->Dom[Per domain when large]; Buckets-->Merge[Merge shared domains]; Svc-->Col[Materialized collections]; Dom-->Col; Merge-->Col; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class Col accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="ready"> #mermaid-diagram--r7v-{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-diagram--r7v- .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-diagram--r7v- .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-diagram--r7v- .error-icon{fill:#552222;}#mermaid-diagram--r7v- .error-text{fill:#552222;stroke:#552222;}#mermaid-diagram--r7v- .edge-thickness-normal{stroke-width:1px;}#mermaid-diagram--r7v- .edge-thickness-thick{stroke-width:3.5px;}#mermaid-diagram--r7v- .edge-pattern-solid{stroke-dasharray:0;}#mermaid-diagram--r7v- .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-diagram--r7v- .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-diagram--r7v- .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-diagram--r7v- .marker{fill:#444444;stroke:#444444;}#mermaid-diagram--r7v- .marker.cross{stroke:#444444;}#mermaid-diagram--r7v- svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-diagram--r7v- p{margin:0;}#mermaid-diagram--r7v- .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#mermaid-diagram--r7v- .cluster-label text{fill:#000000;}#mermaid-diagram--r7v- .cluster-label span{color:#000000;}#mermaid-diagram--r7v- .cluster-label span p{background-color:transparent;}#mermaid-diagram--r7v- .label text,#mermaid-diagram--r7v- span{fill:#000000;color:#000000;}#mermaid-diagram--r7v- .node rect,#mermaid-diagram--r7v- .node circle,#mermaid-diagram--r7v- .node ellipse,#mermaid-diagram--r7v- .node polygon,#mermaid-diagram--r7v- .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-diagram--r7v- .rough-node .label text,#mermaid-diagram--r7v- .node .label text,#mermaid-diagram--r7v- .image-shape .label,#mermaid-diagram--r7v- .icon-shape .label{text-anchor:middle;}#mermaid-diagram--r7v- .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-diagram--r7v- .rough-node .label,#mermaid-diagram--r7v- .node .label,#mermaid-diagram--r7v- .image-shape .label,#mermaid-diagram--r7v- .icon-shape .label{text-align:center;}#mermaid-diagram--r7v- .node.clickable{cursor:pointer;}#mermaid-diagram--r7v- .root .anchor path{fill:#444444!important;stroke-width:0;stroke:#444444;}#mermaid-diagram--r7v- .arrowheadPath{fill:#333333;}#mermaid-diagram--r7v- .edgePath .path{stroke:#444444;stroke-width:2.0px;}#mermaid-diagram--r7v- .flowchart-link{stroke:#444444;fill:none;}#mermaid-diagram--r7v- .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--r7v- .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-diagram--r7v- .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--r7v- .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-diagram--r7v- .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-diagram--r7v- .cluster text{fill:#000000;}#mermaid-diagram--r7v- .cluster span{color:#000000;}#mermaid-diagram--r7v- div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-diagram--r7v- .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#mermaid-diagram--r7v- rect.text{fill:none;stroke-width:0;}#mermaid-diagram--r7v- .icon-shape,#mermaid-diagram--r7v- .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--r7v- .icon-shape p,#mermaid-diagram--r7v- .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-diagram--r7v- .icon-shape .label rect,#mermaid-diagram--r7v- .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--r7v- .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-diagram--r7v- .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-diagram--r7v- :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-diagram--r7v- .accent>*{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--r7v- .accent span{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--r7v- .accent tspan{fill:#15152A!important;} Repo scan Endpoints and services Derive buckets Per service Per domain when large Merge shared domains Materialized collections • [The collection overview](https://docs.getelva.ai/api-collections/the-collection-overview.md): Open any collection and you land on a command center, not a file listing : who consumes this API, how it is secured, what changed recently, who owns the code, and how close it is to agent-ready. Every panel is computed from your source and your git history — none of it is hand-maintained, and all of it refreshes on the next scan. A header that already knows your API Before you scroll, the top of the page has introduced the collection better than most READMEs: The name and an auto-written summary of what the endpoints actually do (for a Billing collection: “reads, deletes, creates external-customer, checkout-session, check-subscription, auth”). The owner — the engineer with the most commits to this collection’s source files, not whoever created the page. Two badges pinning exactly what you are looking at: the commit the collection was built from and the OpenAPI version of its spec. Three signals, front and center Three cards sit above the fold because they answer the three questions every API owner gets asked. Who's consuming How many frontend pages and components call this API — and how many endpoints nothing calls at all. Security Posture Auth coverage, endpoints with no auth defined, and whether HTTPS is enforced. MCP Server Expose this collection's operations as agent-callable tools, one click from the overview. Who’s consuming comes from Elva’s cross-reference pass over your own source: it counts the frontend pages and components that reach this API through its request wrappers, and flags unused endpoints that nothing references. This is consumption data most teams simply do not have — and it is the difference between “can I change this?” being a guess or a lookup. Security Posture reads the contract the way an attacker would: what share of endpoints declare auth ( auth coverage ), how many define no auth at all , and whether HTTPS is enforced . A collection showing 0% auth coverage across 16 endpoints is not a style issue — it is a finding, surfaced before any agent or attacker finds it for you. MCP Server closes the loop: the same collection you are auditing becomes a hosted MCP server without leaving the page, so “agent-ready” is a button, not a project. Read the first two cards together. An endpoint that is both unused and unauthenticated is pure attack surface — nobody depends on it, and nothing protects it. The overview puts both signals on the same screen so those endpoints have nowhere to hide. Recent changes, mapped to endpoints The overview’s change feed is not a wall of commit messages. Elva reconstructs it from git history and maps each commit to the exact endpoints it touched , so an entry reads like an API changelog: the commit message, a method-and-path badge such as POST /stripe-webhook , and when it happened. Release commits, version bumps, and bot noise are filtered out before anything reaches the feed. That means “what changed in Billing last month?” is answered by scrolling, not by git log archaeology across a monorepo. The details rail Down the side, the rail compresses the collection’s health into numbers you can act on: Title Description Signal What it tells you Score & grade The 0–100 quality score and A–F grade from the review engine — a 35/100 (F) is a to-do list, not a judgment Tags The domain labels this collection carries in the catalog Repository A direct link to the source repo the collection was scanned from Errors & warnings Open findings from the quality checks, so zero means zero Source coverage How many endpoints are backed by a real source file versus spec-only — "16 with source, 0 without" is full traceability Last scanned How fresh everything on this page is Ownership you can act on The bottom of the rail answers the 2 a.m. question — who do I ping? Last commit : author, avatar, message, and a link straight to the commit on GitHub. Recent contributors : everyone who has touched this collection’s source files recently, identity-matched across git logins, names, and emails so one person does not appear three times. The owner at the top is computed the same way — most commits to the collection’s files, with release and bot commits excluded — so credit lands on the engineer who wrote the code, not the one who cut the release. This page is what "living catalog" means in practice: consumption, security, changes, and ownership recomputed on every scan. Documentation that maintains itself is documentation that stays true. Where to go next Endpoint intelligence Drill from the overview into any endpoint: source file, request wrapper, and every component that uses it. API testing Fire a real request at any endpoint on this page without leaving the browser. • [Endpoint intelligence](https://docs.getelva.ai/api-collections/endpoint-intelligence.md): Most API catalogs stop at a method and a path. Elva keeps going: for every endpoint it can tell you which file defines it, which request wrapper calls it, which pages and components render its data, and whether anything uses it at all — with file paths and line numbers, mapped statically from your own source on every scan. W["Wrapper: getProjectExternalCustomers"]; W-->C["Component: AccessManagementTab.jsx:142"]; E-.->S["Source: auth.requests.js:49, static, 0.85 confidence"]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class E accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="ready"> #mermaid-diagram--rbr-{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-diagram--rbr- .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-diagram--rbr- .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-diagram--rbr- .error-icon{fill:#552222;}#mermaid-diagram--rbr- .error-text{fill:#552222;stroke:#552222;}#mermaid-diagram--rbr- .edge-thickness-normal{stroke-width:1px;}#mermaid-diagram--rbr- .edge-thickness-thick{stroke-width:3.5px;}#mermaid-diagram--rbr- .edge-pattern-solid{stroke-dasharray:0;}#mermaid-diagram--rbr- .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-diagram--rbr- .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-diagram--rbr- .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-diagram--rbr- .marker{fill:#444444;stroke:#444444;}#mermaid-diagram--rbr- .marker.cross{stroke:#444444;}#mermaid-diagram--rbr- svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-diagram--rbr- p{margin:0;}#mermaid-diagram--rbr- .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#mermaid-diagram--rbr- .cluster-label text{fill:#000000;}#mermaid-diagram--rbr- .cluster-label span{color:#000000;}#mermaid-diagram--rbr- .cluster-label span p{background-color:transparent;}#mermaid-diagram--rbr- .label text,#mermaid-diagram--rbr- span{fill:#000000;color:#000000;}#mermaid-diagram--rbr- .node rect,#mermaid-diagram--rbr- .node circle,#mermaid-diagram--rbr- .node ellipse,#mermaid-diagram--rbr- .node polygon,#mermaid-diagram--rbr- .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-diagram--rbr- .rough-node .label text,#mermaid-diagram--rbr- .node .label text,#mermaid-diagram--rbr- .image-shape .label,#mermaid-diagram--rbr- .icon-shape .label{text-anchor:middle;}#mermaid-diagram--rbr- .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-diagram--rbr- .rough-node .label,#mermaid-diagram--rbr- .node .label,#mermaid-diagram--rbr- .image-shape .label,#mermaid-diagram--rbr- .icon-shape .label{text-align:center;}#mermaid-diagram--rbr- .node.clickable{cursor:pointer;}#mermaid-diagram--rbr- .root .anchor path{fill:#444444!important;stroke-width:0;stroke:#444444;}#mermaid-diagram--rbr- .arrowheadPath{fill:#333333;}#mermaid-diagram--rbr- .edgePath .path{stroke:#444444;stroke-width:2.0px;}#mermaid-diagram--rbr- .flowchart-link{stroke:#444444;fill:none;}#mermaid-diagram--rbr- .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rbr- .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-diagram--rbr- .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rbr- .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-diagram--rbr- .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-diagram--rbr- .cluster text{fill:#000000;}#mermaid-diagram--rbr- .cluster span{color:#000000;}#mermaid-diagram--rbr- div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-diagram--rbr- .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#mermaid-diagram--rbr- rect.text{fill:none;stroke-width:0;}#mermaid-diagram--rbr- .icon-shape,#mermaid-diagram--rbr- .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rbr- .icon-shape p,#mermaid-diagram--rbr- .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-diagram--rbr- .icon-shape .label rect,#mermaid-diagram--rbr- .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rbr- .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-diagram--rbr- .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-diagram--rbr- :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-diagram--rbr- .accent>*{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rbr- .accent span{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rbr- .accent tspan{fill:#15152A!important;} GET /auth/external-customer/project/:id Wrapper: getProjectExternalCustomers Component: AccessManagementTab.jsx:142 Source: auth.requests.js:49, static, 0.85 confidence • [API testing](https://docs.getelva.ai/api-collections/api-testing.md): Every collection in Elva doubles as a request workbench : fire real HTTP requests at any endpoint straight from the browser and read the live response in milliseconds. A hardened server-side proxy does the sending, so you can hit private staging APIs without fighting CORS, and without leaking a thing. From reading docs to sending requests in one click The usual testing ritual is a context-switch tax: copy a curl command, export to another tool, recreate auth in a local environment, and hope the docs you copied from were current. In Elva there is nothing to set up. Open any endpoint in the catalog, and the request panel is already there, built from the same spec you are reading. Pick a server, fill the blanks, hit send. What the workbench gives you Real requests, real responses. This is not a mock or a sandbox. The proxy sends actual HTTP to your live or staging server, and you get back the real status, headers, body, and timing. Spec-aware by default. Parameters, headers, and body fields are scaffolded from the endpoint's own schema, so a valid request is the starting point, not an achievement. The proxy does the dirty work. Requests are sent server-side, which means no CORS fights in the browser and no need to expose private staging hosts to the public internet. Credentials that stay yours. Auth is attached at send time and never baked into anything shareable. Testing an authenticated endpoint does not mean pasting keys into docs. Why testing lives inside the catalog Standalone API clients drift out of sync with reality because they live apart from the source of truth. In Elva, the request panel is rendered from the same living spec as the docs, the quality score, and the MCP tools, so when a request fails you are one click from the schema line that is wrong, and when you fix the spec the workbench updates with it. It is also the exact surface your agents will call: the endpoint you just exercised by hand is the same one the MCP runtime turns into a tool, which makes a green response here the fastest possible preview of an agent call working in production. Try it on your own API Import a spec, connect a repo, or point Elva at a URL, and every endpoint arrives with its workbench attached. Your first real request is a few minutes away at app.getelva.ai . • [API changelogs](https://docs.getelva.ai/api-collections/api-changelogs.md): Your API changed the moment you shipped a commit. Elva reads that history and turns it into a changelog for you, so every collection carries a living record of what changed, when, and who actually wrote it — with zero manual upkeep. Every time Elva scans a repo, it reconstructs a retroactive changelog straight from the git history of the files that back your endpoints. Because the clone is deepened on the first scan, a brand-new connection already surfaces “what changed lately” for every API you expose. Rebuilt from git on every scan Elva does not wait for the next change after you connect a repo. It reads the recent commit log of each endpoint’s source file, maps those commits to the endpoints they touched, and groups them into a feed with author and timestamp attached. B[Per-file commit log]; B-->C[Map commits to endpoints]; C-->D[Filter release and bot noise]; D-->E[API changelog feed]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class E accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="ready"> #mermaid-diagram--rrj-{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-diagram--rrj- .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-diagram--rrj- .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-diagram--rrj- .error-icon{fill:#552222;}#mermaid-diagram--rrj- .error-text{fill:#552222;stroke:#552222;}#mermaid-diagram--rrj- .edge-thickness-normal{stroke-width:1px;}#mermaid-diagram--rrj- .edge-thickness-thick{stroke-width:3.5px;}#mermaid-diagram--rrj- .edge-pattern-solid{stroke-dasharray:0;}#mermaid-diagram--rrj- .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-diagram--rrj- .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-diagram--rrj- .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-diagram--rrj- .marker{fill:#444444;stroke:#444444;}#mermaid-diagram--rrj- .marker.cross{stroke:#444444;}#mermaid-diagram--rrj- svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-diagram--rrj- p{margin:0;}#mermaid-diagram--rrj- .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#mermaid-diagram--rrj- .cluster-label text{fill:#000000;}#mermaid-diagram--rrj- .cluster-label span{color:#000000;}#mermaid-diagram--rrj- .cluster-label span p{background-color:transparent;}#mermaid-diagram--rrj- .label text,#mermaid-diagram--rrj- span{fill:#000000;color:#000000;}#mermaid-diagram--rrj- .node rect,#mermaid-diagram--rrj- .node circle,#mermaid-diagram--rrj- .node ellipse,#mermaid-diagram--rrj- .node polygon,#mermaid-diagram--rrj- .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-diagram--rrj- .rough-node .label text,#mermaid-diagram--rrj- .node .label text,#mermaid-diagram--rrj- .image-shape .label,#mermaid-diagram--rrj- .icon-shape .label{text-anchor:middle;}#mermaid-diagram--rrj- .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-diagram--rrj- .rough-node .label,#mermaid-diagram--rrj- .node .label,#mermaid-diagram--rrj- .image-shape .label,#mermaid-diagram--rrj- .icon-shape .label{text-align:center;}#mermaid-diagram--rrj- .node.clickable{cursor:pointer;}#mermaid-diagram--rrj- .root .anchor path{fill:#444444!important;stroke-width:0;stroke:#444444;}#mermaid-diagram--rrj- .arrowheadPath{fill:#333333;}#mermaid-diagram--rrj- .edgePath .path{stroke:#444444;stroke-width:2.0px;}#mermaid-diagram--rrj- .flowchart-link{stroke:#444444;fill:none;}#mermaid-diagram--rrj- .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rrj- .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-diagram--rrj- .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rrj- .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-diagram--rrj- .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-diagram--rrj- .cluster text{fill:#000000;}#mermaid-diagram--rrj- .cluster span{color:#000000;}#mermaid-diagram--rrj- div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-diagram--rrj- .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#mermaid-diagram--rrj- rect.text{fill:none;stroke-width:0;}#mermaid-diagram--rrj- .icon-shape,#mermaid-diagram--rrj- .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rrj- .icon-shape p,#mermaid-diagram--rrj- .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-diagram--rrj- .icon-shape .label rect,#mermaid-diagram--rrj- .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rrj- .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-diagram--rrj- .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-diagram--rrj- :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-diagram--rrj- .accent>*{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rrj- .accent span{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rrj- .accent tspan{fill:#15152A!important;} Git history Per-file commit log Map commits to endpoints Filter release and bot noise API changelog feed • [What is an API contract](https://docs.getelva.ai/api-contracts/what-is-an-api-contract.md): Your catalog is what you have . A contract is what you promise . Elva’s API contracts let you carve a curated, versioned, governed slice out of your API surface — cherry-picked from your collections, trimmed to exactly the fields you want to expose, published to every surface your consumers live on, and monitored for drift against the code that backs it. The problem contracts solve The same API serves wildly different audiences, and serving them all from one raw spec fails everyone at once. A partner needs strict versioning and a stable subset; handing them your full internal spec overexposes fields you never meant to share. An internal team needs speed, not ceremony. A public developer needs polish and full documentation. An AI agent needs rich schemas and tool stability — and absolutely should not see your admin endpoints. A contract is the missing layer between your catalog and your consumers: one promise per audience , each with its own surface, its own governance, and its own artifacts. K; U[Users collection]-->K; N[Notifications collection]-->K["Contract: select, trim, version, govern"]; K-->S[Hosted OpenAPI spec]; K-->D[Docs portal]; K-->M[MCP server]; K-->P[SDKs and Postman]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class K accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="ready"> #mermaid-diagram--r21-{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-diagram--r21- .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-diagram--r21- .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-diagram--r21- .error-icon{fill:#552222;}#mermaid-diagram--r21- .error-text{fill:#552222;stroke:#552222;}#mermaid-diagram--r21- .edge-thickness-normal{stroke-width:1px;}#mermaid-diagram--r21- .edge-thickness-thick{stroke-width:3.5px;}#mermaid-diagram--r21- .edge-pattern-solid{stroke-dasharray:0;}#mermaid-diagram--r21- .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-diagram--r21- .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-diagram--r21- .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-diagram--r21- .marker{fill:#444444;stroke:#444444;}#mermaid-diagram--r21- .marker.cross{stroke:#444444;}#mermaid-diagram--r21- svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-diagram--r21- p{margin:0;}#mermaid-diagram--r21- .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#mermaid-diagram--r21- .cluster-label text{fill:#000000;}#mermaid-diagram--r21- .cluster-label span{color:#000000;}#mermaid-diagram--r21- .cluster-label span p{background-color:transparent;}#mermaid-diagram--r21- .label text,#mermaid-diagram--r21- span{fill:#000000;color:#000000;}#mermaid-diagram--r21- .node rect,#mermaid-diagram--r21- .node circle,#mermaid-diagram--r21- .node ellipse,#mermaid-diagram--r21- .node polygon,#mermaid-diagram--r21- .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-diagram--r21- .rough-node .label text,#mermaid-diagram--r21- .node .label text,#mermaid-diagram--r21- .image-shape .label,#mermaid-diagram--r21- .icon-shape .label{text-anchor:middle;}#mermaid-diagram--r21- .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-diagram--r21- .rough-node .label,#mermaid-diagram--r21- .node .label,#mermaid-diagram--r21- .image-shape .label,#mermaid-diagram--r21- .icon-shape .label{text-align:center;}#mermaid-diagram--r21- .node.clickable{cursor:pointer;}#mermaid-diagram--r21- .root .anchor path{fill:#444444!important;stroke-width:0;stroke:#444444;}#mermaid-diagram--r21- .arrowheadPath{fill:#333333;}#mermaid-diagram--r21- .edgePath .path{stroke:#444444;stroke-width:2.0px;}#mermaid-diagram--r21- .flowchart-link{stroke:#444444;fill:none;}#mermaid-diagram--r21- .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--r21- .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-diagram--r21- .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--r21- .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-diagram--r21- .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-diagram--r21- .cluster text{fill:#000000;}#mermaid-diagram--r21- .cluster span{color:#000000;}#mermaid-diagram--r21- div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-diagram--r21- .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#mermaid-diagram--r21- rect.text{fill:none;stroke-width:0;}#mermaid-diagram--r21- .icon-shape,#mermaid-diagram--r21- .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--r21- .icon-shape p,#mermaid-diagram--r21- .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-diagram--r21- .icon-shape .label rect,#mermaid-diagram--r21- .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--r21- .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-diagram--r21- .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-diagram--r21- :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-diagram--r21- .accent>*{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--r21- .accent span{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--r21- .accent tspan{fill:#15152A!important;} Billing collection Contract: select, trim, version, govern Users collection Notifications collection Hosted OpenAPI spec Docs portal MCP server SDKs and Postman • [Create a contract](https://docs.getelva.ai/api-contracts/create-a-contract.md): From blank page to a published, governed contract in six steps — with an AI assistant trained specifically for API contracts riding along the whole way. The wizard walks Define → Compose → Schema → Publishing → Governance → Review, and you can save a draft at any step and come back later. 1 Define: name it and pick your audience Give the contract a name and an optional description, then answer the question that shapes everything else: who is this contract for? Choose Partner Integration, Internal Service, Public API, or AI Agent / MCP. Each card states its defaults up front — visibility, whether publishing requires approval, and which artifacts it produces — so the governance conversation happens at minute one, not after launch. 2 Compose: select collections and endpoints Cherry-pick the contract's surface from your live catalog. Collections expand into their tag groups and method-labeled endpoints, each with a checkbox — check a whole collection, a tag group, or a single DELETE /api/v1/cart/:itemId . Filter by repo or tag, search across everything, or select all. A running footer keeps the count honest: 2 collections · 32 endpoints total . A contract is not one-to-one with a collection. Pull the four partner-relevant endpoints from Billing, two from Users, and one webhook from Integrations — the contract is the curated union. 3 Schema: control field-level exposure For every selected endpoint, decide which fields it exposes : toggle fields on or off, mark them required or optional, and add constraints. PII and internal-only fields arrive pre-flagged, and one-click actions like Exclude PII trim entire categories at once. The full breakdown lives on the field-level exposure page. 4 Publishing: choose the artifacts Decide where the contract materializes: the hosted OpenAPI spec, documentation platforms, an auto-generated MCP server that exposes only contract endpoints, TypeScript and Python SDKs, a Postman collection, and CI/CD hooks like GitHub PR comments. 5 Governance: set the rules and the people Pick a breaking-change policy (block publish, warn and require acknowledgment, or notify only), describe validation rules in plain language, and invite stakeholders by email with a role — Approver, Reviewer, or Consumer. 6 Review: read the promise before you make it A final pass over everything you configured — audience, endpoints, exposed fields, targets, and governance — before the contract is created and versioned. The AI assistant is a co-author, not a chatbot Every step of the wizard carries an assistant panel that is, in its own words, “specially trained for API contracts” — and it does real work: Start from a prompt. On the early steps, tell it what your API should do and it helps you structure the contract — there is a one-click Create an API contract from a prompt shortcut. Fine-tune the schema. On the Schema step it can mark fields as required, edit field properties, update descriptions, and modify schemas. You type “make email required everywhere and drop every internal field” — it does the clicking. The wizard's order is deliberate: audience before endpoints, endpoints before fields, fields before publishing . By the time anything ships, every exposure decision has already been made once, on purpose, by you. Where to go next Field-level exposure & PII The Schema step in depth: per-field toggles, PII and internal flags, and the exposure tally. Publishing targets Spec, docs, MCP, SDKs, Postman, and CI/CD — everything a contract can generate. • [Field-level exposure & PII](https://docs.getelva.ai/api-contracts/field-level-exposure-and-pii.md): Most API tooling stops at “which endpoints.” Elva’s contracts go a level deeper: which fields . Every endpoint in a contract gets a field-by-field exposure decision — on or off, required or optional, constrained or free — with PII and internal-only fields flagged before they can leak into a partner-facing spec or an agent’s tool schema. This is the step where a contract earns its name. An endpoint list says what consumers can call; the field list says exactly what they will see. The field table The Schema step groups your selected endpoints by service — an identity service here, an inventory API there — with each endpoint showing its exposure count at a glance ( 2/2 Fields, 12/15 Fields ). Expand one and every field becomes a row you control: Title Description Column What you control Include checkbox Whether the field exists in this contract at all — unchecked fields vanish from every generated artifact Field & badges The field name, flagged with PII or Internal when it carries sensitive or non-public data Type The field's data type, editable from a dropdown Value An example value consumers and agents will see in the generated spec and docs Description Human-and-model-readable meaning ("User's primary email address") More Mark the field required or add constraints Bulk decisions in one click Nobody wants to toggle 58 checkboxes by hand. Quick actions apply a policy across the whole contract — or, with the “This endpoint only” variant, to a single endpoint, with Restore defaults as the undo: Include all — start from full exposure and trim down. Required only — expose the minimal viable surface. Exclude PII — drop every flagged personal-data field at once. Exclude internal — drop everything marked internal-only. A search fields box gets you to any field in a large contract instantly, and the AI assistant does the same work conversationally — “mark every ID required and exclude all PII” is a sentence, not a session. The tally that keeps you honest The wizard footer carries two numbers everywhere you go: Exposed fields (say, 49/58) and a warning-colored PII Exposed count. If the contract ships with 18 PII fields exposed, that happened in full view — not as a surprise in a security review six months later. Every artifact inherits these decisions. A field you exclude here is absent from the hosted spec, the docs, the SDK types, the Postman collection, and the MCP tools agents call . There is no second copy to forget. This is data governance where it belongs — at contract time, not incident-review time . The moment of exposure is the moment of decision, and the decision is one click. Where to go next Publishing targets Where the trimmed, governed surface materializes: spec, docs, MCP server, SDKs, and tooling. Governance & stakeholders Breaking-change policy, validation rules, and who signs off before a publish. • [Publishing targets](https://docs.getelva.ai/api-contracts/publishing-targets.md): One contract, every surface your consumers live on. Publishing is a checklist, not a project: tick the artifacts you want and Elva generates each one from the same contract source , so your spec, docs, SDKs, and agent tools cannot drift apart — they are all views of one promise. The canonical spec Every contract gets a hosted OpenAPI spec file — the machine-readable contract in JSON or YAML, at a stable URL you can hand to any tool or partner: Hosted contract spec https://api.elva.io/contracts/partner-api/openapi.json This file reflects the contract, not the raw codebase: only selected endpoints, only exposed fields, with your descriptions and constraints baked in. Everything else you can generate Title Description Title Target What you get Status Theneo Publish the contract to your Theneo documentation portal Available Stoplight Push to Stoplight for design-first governance Available SwaggerHub Publish to the SwaggerHub registry Available ReadMe Sync the contract to your ReadMe developer hub Coming soon MCP Server Auto-generated MCP tools — only contract endpoints exposed , with the endpoint count shown on the toggle Available TypeScript SDK Auto-generated, type-safe npm package Available Python SDK Auto-generated pip package Available Postman Collection Import-ready collection with environments and auth Available GitHub PR comment Posts an advisory assessment summary on pull requests Available Mock Server Returns example responses for consumer dev testing Coming soon Missing a platform you need? The Publishing step has a “Looking for a different platform?” box — tell Elva where you want the contract to land and submit the request. The MCP target deserves a closer look Toggling MCP Server turns the contract into a hosted, agent-callable MCP deployment — and this is where the whole contract pipeline pays off. The tools an agent sees are generated from the contract’s endpoints and the contract’s field-level exposure rules , so an AI Agent / MCP contract is your PII-trimmed, description-rich, governance-approved surface — nothing more. The deployment behaves like any hosted MCP server in Elva: it is served through the enterprise MCP gateway , gets a public install page , and reports into MCP insights & logs . Contract-generated artifacts are versioned together. When the contract publishes v1.1.0, the spec URL, the MCP server, and the SDKs all speak v1.1.0 — one version number, every surface. Where to go next The enterprise MCP gateway Where a contract's MCP server runs: auth relay, encrypted credentials, and full call logging. Sync, drift & the changelog What happens to published artifacts when the source code underneath them moves. • [Governance & stakeholders](https://docs.getelva.ai/api-contracts/governance-and-stakeholders.md): A contract is a promise, and promises need enforcement. Elva bakes governance into the contract object itself: what happens when a change would break consumers, which rules the schema must honor, and who gets a say before anything ships. No wiki page of process, no tribal knowledge — the policy travels with the contract. Pick your breaking-change policy The Governance step’s first decision is what Elva should do when a change to the contract — or drift from its sources — would break consumers: Title Description Policy Behavior Block publish A breaking change cannot be published until it is resolved. The strictest setting — the natural choice for partner and public contracts. Warn & Require Ack Publishing proceeds only after someone explicitly acknowledges the breaking change — friction by design, but not a hard stop. Notify only Stakeholders are informed and the publish goes through — right for fast-moving internal contracts. The policy pairs with the audience you chose at Define: Partner Integration, Public API, and AI Agent / MCP contracts default to requiring approval before publish, while Internal Service contracts skip it for speed. Validation rules in plain language Below the policy sits an optional validation rules box where you describe the invariants your contract’s data must respect — in English, not in a rules DSL. Suggestion chips seed the common ones: IDs are UUIDs Emails are valid No empty strings Positive numbers only Write your own on top (“amounts are integer cents”, “dates are ISO 8601”). These rules document the contract’s expectations right where consumers — human and AI — will meet them. Stakeholders, with roles that mean something Governance is people, so the last step is inviting them. Add stakeholders by email, assign each a role , and send the invite: Title Description Role How they participate Approver Signs off — the people your approval-required publishes wait on Reviewer Gets eyes on changes and weighs in without being a gate Consumer The audience — kept informed of versions and changes that affect them Stakeholders live on the contract’s overview page afterward: searchable, role-editable, removable, and countable at a glance. External emails work — your partner’s integration lead can be a stakeholder on the contract they consume. This is the quiet superpower of contracts: the consumers are in the loop by construction. When drift or a breaking change hits, the people who care are already named, already invited, and already watching. Where to go next Sync, drift & the changelog See the policy in action: alerts, acknowledgments, and the version history every publish creates. What is an API contract Back to the concept: audiences, defaults, and everything a contract carries. • [Sync, drift & the changelog](https://docs.getelva.ai/api-contracts/sync-drift-and-the-changelog.md): Every API program has the same dangerous gap: the contract you promised and the code you shipped, slowly growing apart. Elva closes it by construction. Because contracts are composed from live collections , Elva continuously compares the promise against the source — and the moment the code moves, the contract raises its hand. Loudly. Inside a contract Open any contract and the header tells you the state of the promise before you read a single row: the name, the current version badge (V1.0.0), the visibility badge, and — most importantly — the sync indicator: a green “Last synced: 12 days ago” when all is well, a red “Out of sync” when it is not. Edit and Publish sit top-right, and the workspace splits into five tabs: Overview, Intelligence, Changelog, Endpoints, and Settings. The Overview tab is the contract’s dashboard: Published To — every live artifact (the hosted OpenAPI spec file, the MCP server) with its version and copy/open shortcuts. Source API collections — each collection feeding the contract, with how many of its endpoints are in the contract and a per-collection Synced or Drift badge. A contract drawing 21 endpoints from Notifications, 12 from Billing, 7 from Users, and 3 from Integrations shows exactly that. The stats rail — endpoints, stakeholders, source collections, and publish targets at a glance. Stakeholders — the invited people with their roles, searchable and editable in place. When the code moves: active alerts The moment a source collection changes in a way that affects the contract, the overview grows a red banner — “2 active alerts: source drift and breaking change detected” — with a Review changes button, the drifting collection gets its badge, and the Changelog tab lights up. Three kinds of alerts land there: Title Description Title Alert What it means Real example Breaking The source changed in a way that violates the promise consumers depend on Billing API removed tax_breakdown from GET /billing/invoices Drift The source moved away from the contract — not necessarily breaking, but no longer matching Auth Service added required device_id to POST /integrations/connect Sunset warning An endpoint the contract depends on is scheduled to go away, with a countdown Sunsets in 38 days: GET /users/:id/preferences Each alert names the exact endpoint with a method-and-path badge and offers two actions: dismiss it (you have handled it out of band) or Sync — pull the change into the contract and move forward deliberately. What a breaking change is allowed to do — block the next publish, demand an acknowledgment, or just notify — is whatever you chose as the contract’s governance policy. A contract in Elva cannot silently rot. The only way it drifts is loudly — with a named endpoint, a described change, and a one-click path back to sync. Version history: every promise, on the record Below the alerts, the Changelog tab keeps the contract’s full version history. Every publish creates a version entry with its status badge (the live Public version versus Outdated predecessors), the author who published it, and the date — and each version expands for the details. v1.2.0 by one engineer in June, v1.1.0 and v1.0.0 before it: the whole life of the promise, attributable and auditable. That record answers the questions that usually eat an afternoon: what did we promise the partner in March, who approved it, and what changed since? Scroll, don’t archaeology. Triage from the portfolio You do not have to open contracts one by one to find trouble. On the API Contracts list, a drifting contract’s card is flagged with a red Drift badge and outline, right next to its healthy Public and Private siblings. Filter by status and the portfolio becomes a work queue. Drift detection is the payoff of building contracts on top of the living catalog : because collections rebuild from your repos on every scan, the contract is compared against what you actually shipped — not against what someone remembered to update. Where to go next Governance & stakeholders The policy that decides what an alert is allowed to block, and the people it notifies. The living API catalog The always-current source of truth that makes contract drift detectable in the first place. • [The enterprise MCP gateway](https://docs.getelva.ai/agent-ready-with-mcp/the-enterprise-mcp-gateway.md): Agents are becoming your highest-volume API consumers, and MCP is the door they walk through. Elva does not just generate that door, it stands a hosted, enterprise-grade gateway behind it. Every agent call is authenticated, matched against the tools you chose to expose, relayed with encrypted credentials, and logged for audit before your API sees a single byte. Compare that to the do-it-yourself route: a hand-rolled MCP server per API is another service to build, patch, host, and secure. API keys end up pasted into plaintext client configs on developer laptops. And once an agent connects, nobody can say which tools it called, how often, or with what result. Elva by Theneo replaces all of that with one managed control point between every agent and every API you expose. What happens on every single call The diagram above is not a marketing abstraction, it is the literal request path. Four things happen between an agent deciding to act and your API responding: Authentication. The calling client proves who it is before anything else happens. Unknown callers never reach your API. Tool matching. The request is checked against the exact set of tools you chose to expose. If an endpoint is not in the set, it does not exist as far as the agent is concerned. Credential injection. The gateway decrypts your upstream credentials server-side and attaches them in flight. Keys never sit in plaintext client configs on laptops. Structured results and audit. The response goes back to the agent in a clean, typed shape, and the call is logged with client, tool, status, duration, and token usage. Control what agents can touch Exposure is a deliberate choice, not a default. You pick which endpoints become tools, so an agent can read your catalog without ever seeing a delete route. Test mode lets teams and agents exercise the full surface safely before anything touches production, and because the gateway sits between every agent and every API, changing what is exposed is a configuration change, not a redeploy of yet another service. Upstream credentials are stored encrypted and only ever decrypted inside the gateway at call time. Rotating a key is one update in Elva, not a hunt through every developer laptop and client config that ever connected. Answers for the questions security will ask Who called what? Every tool call is attributable: which client, which tool, what status, how long it took, and how many tokens it consumed. When an agent misbehaves, you have the receipts. Where do the keys live? Server-side, encrypted, injected at call time. Nothing sensitive ships to the agent or its host machine. What is the blast radius? Only the tools you exposed, for the clients you authorized. Revoking access is immediate and central. Who patches it? Elva does. The gateway is hosted, so there is no extra service for your team to build, monitor, or keep up to date. One gateway, every agent The same governed surface serves Claude, Cursor, VS Code, Gemini, and Codex, so adopting a new agent platform does not mean a new security review. Generate a hosted MCP server from any collection in your catalog, decide what it exposes, and hand agents a door you actually control. It starts at app.getelva.ai . • [Hosted MCP servers](https://docs.getelva.ai/agent-ready-with-mcp/hosted-mcp-servers.md): Point Elva at a collection, pick the operations you trust, and it ships a hosted MCP server that agents can call over HTTP in one pass. No boilerplate project, no server to run, no runtime to babysit. MCP is the Model Context Protocol : the open contract agents like Claude, Cursor, and VS Code speak to reach external systems. In MCP terms, a tool is a single callable action. Elva turns each operation you select into exactly one tool, so an agent sees your API as a clean list of things it can do, not a spec it has to parse. From collection to callable server Every deployment gets a stable deploymentId in the shape companySlug/mcpSlug , derived from your workspace and the name you give the MCP. That id is the address agents connect to. 1 Pick a collection Open any collection in the catalog and start a new MCP. Elva reads the stored OpenAPI spec and lists every operation as a candidate tool. 2 Name it and select operations Give the MCP a name (the slug is generated from it) and check the operations you want exposed. Each selected operation becomes one tool with an auto-generated name, capped at 64 characters to satisfy Claude's tool-name limit. 3 Set the target and auth Set the upstream base URL and choose how the runtime authenticates to your API. Tune the timeout, pagination, and include/exclude filters if you need to trim the surface. 4 Generate and deploy Elva compiles your selection into an execution schema, stores it, and publishes the deployment with status: published . The response returns the deploymentId , the live runtimeUrl , and the final toolCount . Only the operations you select are exposed. Everything you leave unchecked is stripped from the generated schema, so agents never see endpoints you did not intend to publish. Generation options When you generate a deployment, these knobs shape which operations become tools and how the runtime calls them. Title Description Title Option What it controls Default baseUrl The upstream API the runtime sends requests to First server URL in the spec timeout Per-request timeout budget 30000 ms pagination Adds a pagination helper to list-style operations false includeTags / excludeTags Keep or drop operations by OpenAPI tag none includeMethods / excludeMethods Keep or drop by HTTP method none excludePatterns Drop operations whose path matches a pattern none selectedOperations The explicit set of operations that become tools none selected Readiness checks before you ship During creation, Elva scores each operation for AI-readiness so you know your tools are safe to hand to an agent. Every operation runs three checks: Missing request body schema (error) on POST , PUT , and PATCH operations that define no request body. No response schema (warning) when there is no 200 , 201 , or 204 response defined. No description (info) when the operation has neither a summary nor a description. The score is the share of checks that pass across all operations, graded A (90+), B (80+), C (70+), D (60+), else F . Filter the issue list by severity to fix the errors that matter most before an agent ever calls the tool. What each check protects agents from — and how to raise the grade in one pass — is covered on the AI readiness page. How the hosted runtime serves every call You do not deploy a server per API. A single stateless MCP runtime serves every deployment over HTTP. When an agent calls a tool, the runtime loads that deployment’s execution schema, builds the upstream request from the tool call, forwards it to your API, and returns the response as content the agent can read. • [MCP authentication & OAuth](https://docs.getelva.ai/agent-ready-with-mcp/mcp-authentication-and-oauth.md): Your MCP tools call real APIs, and those APIs want credentials. Elva secures that hop with a stateless token relay : it exchanges and holds tokens in memory to make the upstream call, and never persists your credentials to disk. The runtime supports the auth every real API uses, wires up OAuth 2.0 and OpenID Connect for agents that speak them, and encrypts the tokens it hands back to clients like Claude so raw secrets never leave the server. Relay, not vault. The MCP runtime exchanges and caches tokens in memory only. It does not store your API keys, client secrets, or passwords in any database. Restart the runtime and the token cache is gone. Auth types Elva supports Every hosted MCP server has an Authorization tab where you declare how the tools should authenticate to your upstream API. Pick one type per deployment. Title Description Title Auth type Value What the caller supplies No auth no_auth Nothing. Tools call the API directly. API key api_key The key value. Elva injects it as a header or query param, with a header name you set (default X-API-Key ). Bearer token bearer_token A token, sent as Authorization: Bearer . JWT jwt A signed token, sent as a bearer credential. Basic auth basic_auth Username and password, base64-encoded into Authorization: Basic . OAuth 2.0 oauth_2_0 Client ID + secret (client credentials) or username + password (password grant). Elva exchanges them for an access token. OpenID Connect openid_connect An issuer URL you configure. The user signs in at the provider; Elva completes discovery and the code exchange. For API key auth you also choose the placement: send it as a request header or a query parameter. For bearer and JWT you can set a custom label so the connect screen tells users exactly which token to paste. OAuth 2.0 grant types When you pick OAuth 2.0 , Elva runs one of two grants against your token URL: Client credentials (default): Elva base64-encodes the client ID and secret, POSTs grant_type=client_credentials to your token endpoint, and caches the returned access token. Password : Elva POSTs grant_type=password with the username, password, and any scopes, then caches the token. Authorization code is not yet supported end to end. The runtime and connect form recognize the authorization_code grant but return "Authorization code flow is not yet supported" instead of completing it. Use client credentials or password for OAuth 2.0 today, or OpenID Connect when your provider supports discovery. How the OAuth relay works For Claude custom connectors, the runtime speaks full OAuth 2.0: metadata discovery, dynamic client registration , and PKCE . The agent never sees the real upstream credential. It receives an opaque, encrypted envelope, and the runtime unwraps it only at call time. • [The public install page](https://docs.getelva.ai/agent-ready-with-mcp/the-public-install-page.md): The moment you deploy an MCP server, Elva publishes a hosted, public-facing install page for it: a branded landing page where anyone can see exactly which tools your server exposes, pick their client, and connect in under a minute. Think of it as your API’s storefront for the agent era — no README to write, no onboarding doc to maintain, no “how do I connect this?” tickets. You host nothing. Elva renders the page from your deployment and your settings, and it updates the instant either one changes. Live at a predictable URL Every deployment’s page is reachable the moment it goes live, at an address built from its deploymentId : Install page URL https://app.getelva.ai/mcp/:companySlug/:mcpSlug/install Prefer something you can say out loud? Set a custom slug in the MCP settings and the same page answers at a short vanity path: Custom slug URL https://app.getelva.ai/mcp/:customSlug/install What a visitor sees The page is one scroll, ordered the way a connecting developer thinks: what is this → how do I connect → what can it do . Title Description Section What it shows Brand header Your logo, the server's name, the live MCP endpoint with one-click copy, and a documentation button styled in your primary color Connect your MCP client Six client tabs — Claude Desktop, Claude Code, Cursor, VS Code, Gemini CLI, Codex CLI — each with a numbered installation guide and copy-paste commands Available tools Every exposed tool with its HTTP method, path, tag, description, and tool ID — plus live search and tag filtering Raw configuration The plain mcpServers JSON block, for advanced users and clients not in the list Two details do a lot of quiet work here: The install steps adapt to your auth. A server configured for OAuth walks the visitor through it — run the add command, then /mcp → select the server → Authenticate , approve in the browser, done. A header-authenticated server shows the exact environment variables to export instead. Visitors never have to figure out which flow applies; the page already knows. The tool list is full disclosure. Method, path, description, and tool ID for everything the server exposes — searchable and filterable by tag. A developer (or their security reviewer) sees precisely what an agent will be able to call before anything connects. That transparency is what makes the page shareable outside your team. So the visitor’s whole journey is three moves: 1 Open the link You share one URL — in your docs, a partner email, a launch post. No account needed to view a public page. 2 Pick a client, paste the setup The visitor selects their client tab and runs the command or pastes the JSON, copy button included. 3 Authenticate and go They complete the auth flow the page walked them through, their agent lists your tools, and the first call lands in your logs. Make it yours Admins customize the page from the MCP server’s Settings tab, under Install Page Branding . Four controls cover the whole surface: Title Description Control What it does MCP Logo Upload an SVG, PNG, or JPG ; it renders in the page header next to the server name Primary Color Pick from the ten-swatch palette or use the eyedropper for any custom hex; it drives the page's accents, including the documentation button Documentation link A link to your own MCP documentation, featured at the top of the page Documentation label What that button says — "View Docs", "API Reference", whatever fits your voice Hit Customize and the change is live for everyone holding the link. The page is a live view of your settings, not a build artifact — there is no publish step, no cache to bust, no stale copy of your onboarding floating around. Decide who sees it The same Settings tab controls visibility , so the storefront can be as open or as gated as the API behind it: Title Description Title Visibility Who can open it Behavior Public Anyone with the link Page and tool list load immediately. This is the default. Private Anyone with the password The page returns 401 { requiresPassword: true } until a valid install token is presented. Disabled No one The endpoint responds with 404 as if it does not exist. Private pages are password-gated, not credential-gated. A visitor enters the password once; Elva bcrypt-checks it and issues a signed install token valid for 24 hours, which unlocks the page and its tool list. The upstream API credentials your tools actually use are handled separately by the MCP gateway and never appear on this page. This page is the distribution half of going agent-ready: the gateway makes your API safe to expose, and the install page makes it easy to adopt. Share one link and every visitor onboards themselves. Where to go next Connect any MCP client The exact commands and JSON the page generates for all six clients, and what the auth headers do. MCP insights & logs Watch who connects after you share the link: per-agent activity, call volume, and the full call log. • [MCP insights & logs](https://docs.getelva.ai/agent-ready-with-mcp/mcp-insights-and-logs.md): Agents do not file support tickets. When a tool call fails, loops, or slows to a crawl, the only witness is the wire — so Elva records it. Every hosted MCP server ships with observability for the agent era : per-agent activity, per-tool health, latency percentiles, token metering, and a call-by-call log, with zero instrumentation on your side. Your MCP server, six tabs Open any MCP server in Elva and everything about it lives in one workspace. Insights and Logs are the observability half. Title Description Tab What it holds Overview The server's identity: name, visibility badge, and the live MCP URL agents connect to Tools Every operation you exposed as a tool, exactly as agents see it Authorization How the gateway authenticates to your upstream API Insights Rolled-up metrics: requests, latency, errors, tokens, agents, and per-tool breakdowns Logs The raw feed — one entry per tool invocation Settings Branding, visibility, custom slug, and the public install page configuration Four numbers that tell you if agents are winning The top of the Insights tab answers the health question at a glance, over a rolling 24-hour window: Title Description Metric What you learn Total requests (24h) Demand, with a day-over-day trend so a spike or a silence stands out immediately Avg response time Typical speed, paired with P95 — the tail latency agents actually feel when they chain tool calls Error rate The share of failed calls, with the failed-versus-total count behind it Token usage Aggregate tokens plus the average per call — the cost signal for agent traffic Agents retry. A human hits a broken endpoint once and gives up; an agent may hammer it in a loop. That is why error rate and token usage sit on the same row — a failing tool is usually also an expensive one. Agent activity: who is actually using your API This is the adoption dashboard most API teams have never had. Elva auto-detects each calling client from its requests — claude , cursor , windsurf , copilot , or the raw identifier for anything else, such as openai-mcp/1.0.0 (Codex) — and renders a card per agent: Last seen — how recently the agent called, from minutes to days. Calls today — the volume this agent is driving. Tools used — how much of your surface it has discovered and adopted. You do not tag anything and agents do not register. They connect, they call, and they appear. This is the question every platform team is about to be asked: "which AI assistants use our API, and for what?" With Elva the answer is a screen, not a research project. Drill-down panels: from symptom to culprit Below the headline metrics, four expandable panels break the same 24 hours down by key, tool, and failure mode: Title Description Panel The question it answers API Key Usage (24h) Which credentials are driving the traffic — and which issued key nobody uses Most Error-Prone Tools Which tools fail most, their top error, and the agent hitting them hardest Slowest Tools (P95) Where the latency tail lives, with P50 / P95 / P99 per tool Top Tools by Volume (24h) What agents actually lean on — often not the endpoints you expected The Logs tab: every call, on the record Insights are rollups; Logs are the evidence. The gateway writes one entry for every tool invocation it serves — the detected client, the tool name, the upstream status code, the round-trip duration, and the timestamp — so nothing an agent does is a black box. That single feed does double duty: Debugging. A tool started failing at 14:02? The log shows which agent, which arguments pattern, and which upstream status — before your first guess. Audit. When security asks “what exactly did the agent touch,” you scroll, you do not reconstruct. Prefer push over pull? MCP webhooks deliver server activity to your own endpoints — Slack, PagerDuty, SIEM — the moment it happens. See the Admin & management section. From signal to fix The views are designed to chain, so a bad metric turns into a shipped fix in minutes: 1 Spot the symptom The error-rate tile jumps — say 36% of calls failing in the last 24 hours. 2 Find the culprit Open Most Error-Prone Tools . One tool owns nearly all the failures, and the panel names its top error and the agent driving it. 3 Read the evidence Jump to Logs and filter your eyes to that tool: the status codes tell you whether it is a 401 (auth), a 422 (schema), or a 500 (your API). 4 Fix at the source Auth failures point at the Authorization tab; malformed-argument failures point at the operation's schema and descriptions — see AI readiness. 5 Watch it recover The 24-hour window rolls forward and the error rate falls with it. No deploy, no dashboard to build. While a deployment warms up, some dashboards render illustrative sample data alongside your real logs so the layout is never empty. Read them as capability types rather than exact figures until your own traffic fills in. FAQ What counts as a connected agent? Any client the gateway identified and logged in the last 24 hours . Elva counts distinct client names over that window, so an assistant that called yesterday but not today drops off the live count while its history stays in the logs. How are Claude, Cursor and other clients told apart? The gateway inspects each incoming request and classifies the caller. Recognized clients map to friendly names like claude , cursor , windsurf and copilot ; anything else is logged under its raw client identifier so it is never lost. Where do the numbers come from? Every metric on the Insights tab is aggregated from the per-call log the gateway writes on each invocation — the same entries you can read raw on the Logs tab. One source of truth, two zoom levels. Where to go next The enterprise MCP gateway The control point that writes these logs: auth relay, encrypted envelopes, and tool-level exposure control. AI readiness Fix the schema and description gaps behind malformed-argument failures before agents hit them. • [AI readiness](https://docs.getelva.ai/agent-ready-with-mcp/ai-readiness.md): “Agent-ready” is a claim most APIs cannot back up. Elva makes it a measured grade : every operation is checked for the schemas, descriptions, and semantics an LLM needs before it can call your API safely — and every MCP server shows you that grade before you ship it to a single agent. Why agents need more than a valid spec A human developer who hits a vague endpoint reads the source, asks a teammate, or experiments in a sandbox. An agent does none of that. It reads your contract once and acts, which turns every gap in the spec into a runtime failure: No request body schema → the agent invents a payload shape, and your API rejects it — or worse, accepts it. No description → the agent picks tools by name alone, and POST /process gets called for everything. No response schema → the agent cannot interpret what came back, so it guesses, retries, and burns tokens. Validity is table stakes. Readiness is whether a model can ground itself in your API without a human in the loop — and that is what Elva scores. The readiness check on every MCP server When you generate an MCP deployment, Elva runs every selected operation through readiness checks and grades the result, so weak tools are caught at build time, not in an agent’s transcript. Title Description Title Check Severity What goes wrong for the agent Missing request body schema Error A POST , PUT , or PATCH with no body schema forces the model to hallucinate the payload No response schema Warning No 200 , 201 , or 204 response defined, so the model cannot reason about results No description Info Neither summary nor description, so tool selection runs on the name alone The readiness score is the share of checks that pass across all selected operations, graded A (90+), B (80+), C (70+), D (60+), else F . Filter the issue list by severity and burn down the errors first — they are the ones that produce hallucinated payloads. A weak tool does not fail loudly. It fails as an agent that seems dumb — wrong arguments, wrong tool choices, wasted tokens — and your API gets the blame. Readiness scoring moves that failure from the agent's transcript to your build screen, where it is fixable. AI Readiness in the spec score Readiness is not bolted on at MCP time — it is one of the four categories in Elva’s spec quality engine, weighted at 15% of the overall grade and scored by deterministic checks: Title Description Check family What it measures ai-op-ids Every operation has a clean, unique operationId a model can reference ai-op-semantics Summaries and descriptions say what an operation does , not just what it is called ai-schema-richness Schemas carry constraints, enum documentation, and format specifications instead of bare string fields Because both surfaces reuse the same deterministic engine, the story is consistent: the grade on your collection, the score on the Insights page, and the readiness check on your MCP server all move together when you fix the spec. Raise the grade in one pass 1 Name every operation Add a unique, descriptive operationId and a one-line summary per operation. This alone transforms tool selection. 2 Schema the writes Give every POST , PUT , and PATCH a request body schema. This clears the error-severity readiness check. 3 Schema the reads Define the success response ( 200 / 201 / 204 ) so agents can parse what they get back instead of guessing. 4 Constrain the inputs Add enums, formats, and min/max bounds. Every constraint you declare is an invalid call an agent never makes. 5 Rescore and ship Scoring is deterministic — the same spec always earns the same grade — so you can watch each fix move the exact category it should, then deploy the MCP server knowing what agents will experience. This loop is Elva's core promise in miniature: agent-ready is earned, not assumed — and once earned, it is enforced by the same pipeline that deploys your tools. Where to go next Spec quality & scoring The full engine: 30+ checks, four weighted categories, and how a percentage becomes a grade. Hosted MCP servers Where the readiness check runs: select operations, set auth, and deploy an agent-callable server. • [Spec quality & scoring](https://docs.getelva.ai/quality-and-scoring/spec-quality-and-scoring.md): Every spec Elva scores gets a grade you can actually defend, because the number comes from 30+ deterministic checks , not a vibe. Here is exactly how the review engine turns your OpenAPI spec into a percentage and a letter grade, so you trust the score before you expose an API to agents. The four categories that make your score The review engine runs every check against your parsed spec and rolls the results into four weighted categories: Design , Developer Experience , AI Readiness , and Security . Design carries the most weight, because a poorly shaped API breaks agents and humans alike. AI Readiness is scored explicitly, so an "agent-ready" claim is earned, not assumed. Design Weight 40. URI naming, HTTP method semantics, status codes, pagination, versioning, idempotency, and response completeness. The heaviest category, because a poorly shaped API breaks agents and humans alike. Developer Experience Weight 35. Executable examples, operation and parameter descriptions, a consistent error model, and overall spec integrity. The category that decides how fast a human ships against your API. AI Readiness Weight 15. OperationId quality, semantic descriptions, schema richness, constraints, enum docs, and format specification. How well an LLM can ground itself in your spec. Security Weight 10. HTTPS enforcement, declared auth schemes, strong auth methods, 401/403 coverage, rate-limit docs, and secret hygiene. The checks your security review runs anyway, run early. AI Readiness is a scored category, never an assumption. Checks like ai-op-ids , ai-op-semantics , and ai-schema-richness measure how well an LLM can ground itself in your spec. The tools you hand to Claude or Cursor are only as trustworthy as this score. How a score is computed Each check returns one of three outcomes, and each outcome carries a fixed multiplier against that check’s weight: Title Description Title Outcome Value Surfaces as Pass 1.0 (clean) Partial 0.5 a warning Fail 0.0 an error A category’s percentage is the weighted pass ratio : the sum of outcome × weight for its checks, divided by the total weight of those checks. The overall score is the category-weighted average across all four categories, using the 40 / 35 / 15 / 10 weights above. • [The check catalog](https://docs.getelva.ai/quality-and-scoring/the-check-catalog.md): Every grade Elva assigns comes from a fixed catalog of 30+ concrete checks , each with an id, a category, a severity, and a weight. This is the whole list, so you can see exactly what moves your score and why it matters when an agent is on the other end of the call. Each check runs against your parsed OpenAPI spec and returns Pass , Partial , or Fail . That result is multiplied by the check weight and rolled into one of four categories: Design, Developer Experience, AI Readiness, and Security. The higher the weight, the harder that single check pulls your grade. These are the exact same checks that drive MCP readiness . When Elva flags a tool as risky to expose to an agent, it is these checks talking. Fix them in the spec and both your catalog grade and your MCP readiness improve together. You can pull this catalog live from the public API: GET https://api.getelva.ai/api/review/checks returns every entry below with its id , category , name , description , severity , and weight . AI Readiness These checks exist because an agent reads your spec the way a developer never would: literally, and at scale. Vague operationIds, undocumented enums, and missing formats are exactly what cause an LLM to hallucinate a call. This category is where “agent-ready” is earned. Title Description Title Description id Name Severity Weight ai-op-ids OperationId Quality high 9 ai-op-semantics Semantic Operation Descriptions medium 6 ai-schema-discoverability Schema Discoverability medium 6 ai-schema-richness Schema Field Metadata medium 5 ai-parameter-constraints Parameter Constraint Coverage medium 5 ai-format-specification Format Specification medium 5 ai-context-anchors LLM Context Anchors medium 4 ai-enum-documentation Enum Documentation medium 4 Developer Experience Humans still integrate your API, and their experience is a proxy for how legible the contract is. Missing examples, ad-hoc error shapes, and undescribed parameters make the spec harder for people and agents alike. spec-integrity sits here and carries the heaviest weight in the category. Title Description Title Description id Name Severity Weight spec-integrity OpenAPI Integrity & Reuse high 9 dx-executable-examples Executable Examples high 8 dx-error-schema Consistent Error Model high 8 dx-op-descriptions Operation Descriptions Present medium 7 dx-param-doc Parameter & Schema Descriptions medium 6 dx-accessibility-docs Docs Accessibility Basics low 2 Design The largest category by overall weight. This is where REST hygiene lives: nouns not verbs, correct method semantics, real status codes, pagination, and consistent identifiers. design-method-semantics is the single most influential check in the whole engine. Title Description Title Description id Name Severity Weight design-method-semantics HTTP Method Semantics & Idempotency high 9 design-status-codes Status Codes in Spec medium 7 design-pagination Pagination Style & Docs medium 6 design-resource-identifier-consistency Resource Identifier Consistency medium 6 design-uri-naming Resource URI Naming medium 5 design-content-negotiation Content Types & Accept medium 5 design-response-schema-completeness Response Schema Completeness medium 5 design-versioning URI or Spec Versioning medium 4 ops-deprecation Deprecation & Sunset medium 4 design-async-lro Long-Running Operations medium 4 design-idempotency-key Idempotency for Risky POSTs medium 4 design-webhooks Webhook Contracts medium 4 design-consistent-naming Consistent Casing & Separators medium 3 design-filtering-fields Filtering, Sorting & Sparse Fieldsets low 3 Security An agent you expose to the world is only as safe as the contract behind it. These checks confirm HTTPS, declared auth schemes, documented 401/403 and 429 responses, and no secrets leaking through examples. Title Description Title Description id Name Severity Weight sec-https-only HTTPS Enforcement high 8 sec-auth-schemes-defined Auth Schemes Declared high 8 sec-strong-auth Secure Auth Methods medium 5 sec-unauth-responses Unauthorized/Forbidden Codes medium 5 sec-secrets-hygiene Secrets in Examples medium 4 sec-rate-limit-spec Rate Limit Documentation medium 3 What moves the score most Weight is the lever. A handful of high-severity checks (weight 8 to 9) dominate every grade, so if you want the fastest lift, start here: design-method-semantics (w9) and spec-integrity (w9) ai-op-ids (w9) dx-executable-examples (w8) and dx-error-schema (w8) sec-https-only (w8) and sec-auth-schemes-defined (w8) Clearing these turns the biggest Fails into Passes and pulls the category percentages up hard. The lighter checks (weight 2 to 4) refine an already solid spec rather than rescue a broken one. FAQ Why does AI Readiness get its own category? Because agents fail differently than humans. A person can guess that POST /createUserV2 makes a user; an LLM planning a tool call needs a stable operationId, typed constraints, documented enums, and explicit formats to avoid inventing invalid arguments. Checks like ai-op-ids , ai-parameter-constraints , and ai-enum-documentation measure exactly that, so the tools you expose over MCP are ones agents can actually call correctly. What does a Partial result mean? Each check scores Pass = 1.0 , Partial = 0.5 , or Fail = 0.0 , then multiplies by its weight. Partial means you satisfy the check across most of your spec but not the threshold for a full pass. For example, a coverage check that wants descriptions on 90% of parameters returns Partial when you are close but short. Partials surface as warnings; Fails surface as errors. Do these same checks drive MCP readiness? Yes. The review engine is the single source of truth. The grade on your collection sidebar, the category bars on the Insights page, and the per-tool readiness shown when you generate a hosted MCP all come from this one catalog. Improve a check once and it lifts everywhere. Can I see the full catalog programmatically? Call GET https://api.getelva.ai/api/review/checks with no auth. It returns the complete list with descriptions, so you can wire the catalog into your own CI or dashboards. • [Score a spec via API](https://docs.getelva.ai/quality-and-scoring/score-a-spec-via-api.md): Paste a spec, get a grade. Elva’s scoring engine runs as a public HTTP API at https://api.getelva.ai so you can score any OpenAPI document straight from your terminal, with no account and no key. Two endpoints are open to everyone: GET /api/review/checks and POST /api/review . Everything else in Elva's API (repos, catalog, collections, MCP, chat, testing) sits behind authentication and runs inside the app. Score first, sign up later. List the check catalog GET /api/review/checks returns the full set of checks the engine runs, so you can see exactly what your spec is graded against before you submit anything. Each entry carries an id , category , name , description , severity , and weight . Terminal curl https://api.getelva.ai/api/review/checks The response is a flat array. A single element looks like this: One check { "id": "design-method-semantics", "category": "Design", "name": "HTTP Method Semantics & Idempotency", "description": "GET has no requestBody; PUT/DELETE are idempotent; PATCH is partial; POST is non-idempotent unless protected by Idempotency-Key.", "severity": "high", "weight": 9 } Score a spec POST /api/review takes your OpenAPI document and hands back category scores, a full per-check breakdown, and an overall grade. You can send the spec two ways, and the engine handles both transparently. text/plain (raw YAML or JSON) application/json (parsed object) The simplest path: stream a spec file straight from disk. The body is the raw file contents, whether that is YAML or JSON. Terminal curl -X POST https://api.getelva.ai/api/review \ -H "Content-Type: text/plain" \ --data-binary @openapi.yaml Already holding a parsed spec? Send it as a JSON body and the engine serializes and scores it the same way. Terminal curl -X POST https://api.getelva.ai/api/review \ -H "Content-Type: application/json" \ --data-binary @openapi.json What comes back A successful call returns one object with four top-level fields. scores breaks the result out by the four weighted categories, checks lists every individual check result, and overallScore / overallGrade roll it all up. 200 OK { "scores": { "Design": { "percentage": 82, "grade": "B" }, "DeveloperExperience": { "percentage": 74, "grade": "C" }, "AIReadiness": { "percentage": 66, "grade": "C" }, "Security": { "percentage": 90, "grade": "A" } }, "checks": [ { "category": "AIReadiness", "id": "ai-op-ids", "status": "Pass", "comments": "All operations expose descriptive operationIds.", "weight": 9 } ], "overallScore": 79, "overallGrade": "B" } Each check reports status as Pass , Partial , or Fail , scored 1.0 , 0.5 , and 0.0 respectively and multiplied by its weight . Category percentages are weighted pass ratios; the overall score is the category-weighted average (Design 40, Developer Experience 35, AI Readiness 15, Security 10). Grades follow: A ≥ 88, B ≥ 76, C ≥ 64, D ≥ 50, otherwise F. Response fields Field Type Description scores object Per-category result keyed by Design , DeveloperExperience , AIReadiness , Security . scores..percentage number Weighted pass ratio for the category, rounded to a whole number. scores..grade string Letter grade ( A – F ) derived from the category percentage. checks array One entry per check that ran. checks[].id string Check identifier, e.g. dx-executable-examples . checks[].category string The category the check belongs to. checks[].status string Pass , Partial , or Fail . checks[].comments string Human-readable notes about what passed or failed. checks[].weight number The check’s contribution to its category score. overallScore number Category-weighted average across all four categories. overallGrade string Overall letter grade. Error responses The endpoint fails fast and tells you why. Both errors return a JSON body with a single error field. Status When it happens 400 The request body is missing or could not be read as a spec. 422 The body parsed, but it is not a valid OpenAPI document. The same engine and the same checks drive the scores you see on the Insights page, the collection sidebar, and MCP readiness. Scoring from the terminal gives you the exact grade Elva will assign once your API lands in the catalog. • [AI assistant & semantic search](https://docs.getelva.ai/work-with-ai/ai-assistant-and-semantic-search.md): Stop grepping your specs. Ask a question in plain English and Elva’s chat agent searches, retrieves, and answers straight from your live catalog — grounded in the real operations, schemas, and security of the APIs you can access. Ask Elva about your catalog; it retrieves the real spec before it answers. Chat that actually reads your specs The assistant is a RAG (retrieval-augmented) agent , not a chatbot that hallucinates endpoints. When you ask a question, it runs a tool-calling loop over the collections you have access to, pulls the exact spec content it needs, and answers from that evidence. The system prompt is explicit: gather information with tools first, never guess endpoint names, fields, or counts. It runs in-app through POST /api/ai/chat , scoped to your account. Every answer is limited to the collections you can see, and the assistant automatically attaches your active collection context so questions about the API you are looking at just work. Responses can stream token by token, and each one carries the source chunks it was built from. Prompt-injection guard. Retrieved spec content is wrapped and labeled as data, not instructions. The agent is told to obey only your request and the system prompt, never anything embedded inside a tool result or a spec. A malicious description in someone's OpenAPI file cannot hijack the assistant. The agent’s toolbox Instead of stuffing an entire spec into the model, the agent picks the right tool for the job. Each tool is access-checked against the collections you own before it returns anything. Tool What it does Returns search_spec Semantic search across one collection or every accessible collection Up to 8 best-matching chunks with sources list_endpoints Full enumeration of a chunk kind (default operation ) with optional method or tag filter Up to 100 matching entries get_endpoint_details Fetch one operation by operationId, chunkId, pointer, or path The full operation content list_my_collections List the collections you can access Names and ids find_usages Count $ref usages of a named component across the reference graph Up to 100 referencing chunks keyword_search Exact substring match over path, name, pointer, and content Up to 25 hits How a question becomes a grounded answer The agent runs up to three tool rounds at temperature 0, then makes a final answer call. Sources are de-duplicated by collection and chunk id before they come back to you. E[Embed query]; E-->R[Retrieve chunks]; R-->T[Tool calls: search / list / usages]; T-->G[Grounded answer + sources]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class G accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="rendering"> graph LR; Q[Your question]-->E[Embed query]; E-->R[Retrieve chunks]; R-->T[Tool calls: search / list / usages]; T-->G[Grounded answer + sources]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class G accent; • [AI-assisted spec editing](https://docs.getelva.ai/work-with-ai/ai-assisted-spec-editing.md): Describe a change in plain language and Elva returns a precise, reviewable edit you can preview as a diff before it ever touches your spec. This is a Monaco-based OpenAPI editor with an AI composer that speaks JSON Patch, so every suggestion is surgical, not a wholesale rewrite. Edit by describing, not hand-typing The composer takes an instruction like “add an email field to the User schema” and returns an RFC-6902 JSON Patch proposal. Elva parses the patch, validates it, and applies it against a copy of your document, so a bad suggestion can never silently corrupt the spec. Under the hood the composer runs applyJsonPatch with validation on and mutation off: the patch is checked with fast-json-patch first, then applied to produce new YAML only if it holds. Because edits are expressed as discrete operations ( add , remove , replace ), they are additive and targeted . The composer adds a property to a schema, appends to a required array, or inserts a single operation. It does not blindly replace whole objects, so your descriptions, examples, and unrelated fields stay intact. Every proposal is a preview first . Nothing is written to your spec until you press Accept all . Reject and the document is untouched. From prompt to applied patch 1 Describe the change Open the composer in the editor and type what you want in plain language, for example "add a cursor pagination parameter to GET /orders ". The composer sends your instruction to Elva's model proxy along with the relevant slices of your spec. 2 Preview the diff Elva returns a patch proposal card summarizing each change ( + add , ~ update , - remove ) with a count of changes in your file. Expand any row with View changes to inspect the exact content that will be added, updated, or removed, rendered as a syntax-highlighted diff. 3 Apply or discard Press Accept all to apply the patch. The editor updates, the card flips to Changes Applied , and Elva jumps you to the first changed line. Press Reject all to discard the proposal with zero side effects. A returned patch is just a JSON array of operations. Here is the shape the composer works with: RFC-6902 JSON Patch [ { "op": "add", "path": "/components/schemas/User/properties/email", "value": { "type": "string", "format": "email" } }, { "op": "add", "path": "/components/schemas/User/required/-", "value": "email" } ] Notice the second operation appends to the required array with /- instead of overwriting it. That is the additive discipline in action: the new field is added and marked required without disturbing the fields already there. Live linting with a Fix with AI shortcut As you type, Elva lints your spec with Spectral against the recommended OpenAPI ruleset and surfaces issues inline in the editor. Each finding carries a severity: error , warning , info , or hint . Every issue comes with a Fix with AI quick-fix. Trigger it and Elva drafts the composer prompt for you from the marker, seeding the composer with the exact rule, message, and location so you can turn a lint failure into an applied patch in one move. Validation runs off the main thread in a Web Worker so the editor stays responsive. For large or heavy specs it transparently offloads to the backend instead of blocking your browser. Condition What happens Spec under ~250,000 characters, fast device Linted locally in the worker Spec over ~250,000 characters Offloaded to the backend linting endpoint Previous run took over 800 ms Offloaded to the backend on the next run Fewer than 4 CPU cores detected Offloaded to the backend Backend unreachable Falls back to local Spectral automatically Choose your model provider Composer and Fix-with-AI calls route through Elva’s multi-provider model proxy . You pick who runs the model, and you can bring your own key or lean on Elva’s shared quota. OpenAI Anthropic Google Route composer requests to OpenAI models through the proxy. Provide your own OpenAI key in AI Model Settings , or leave it blank to use Elva's configured key where available. Use Claude models for spec edits. Supply your own Anthropic key to run on your own quota and billing. Run edits on Gemini models. Elva offers a shared Gemini quota so you can try the composer without a key, and you can switch to your own key any time. Shared quota or your own key. Choose Use Elva's API key to start instantly on shared quota, or Use my API key to run on your own provider account. Custom keys are stored encrypted behind a session passphrase, never in plain text. Details worth knowing What exactly does Fix with AI do? It reads the Spectral marker at your cursor, builds a targeted composer prompt from the rule id, message, and severity, and drafts the edit for you. You still preview the proposed patch as a diff and decide whether to apply it. The lint is never auto-fixed silently. Which Spectral rules run? Elva extends the recommended OpenAPI ruleset out of the box. You can tune which rules are active, toggle individual checks, and adjust severities, so the linting matches your team's house style. Can an AI edit break my spec? No. Proposals are validated as JSON Patch and applied to a copy with validation enabled and mutation disabled. If a patch is malformed, it is rejected before anything is written. You always see the diff and confirm before it lands. Are edits precise or sweeping? Precise. The composer emits granular add , remove , and replace operations scoped to the exact path you want changed. It appends to arrays and inserts single properties rather than replacing entire objects, so surrounding content is preserved. • [MCP webhooks](https://docs.getelva.ai/admin-and-management/mcp-webhooks.md): Dashboards are pull. Operations are push. MCP webhooks push what happens on your hosted MCP servers into the systems your team already lives in — Slack, PagerDuty, your SIEM, your data warehouse — the moment it happens, instead of waiting for someone to open a dashboard. Agents do not keep office hours. They call your tools at 3 a.m., they retry in loops, and they adopt new tools the day a teammate shares an install link. Webhooks close the gap between the gateway logged it and a human found out . How it works You register an HTTPS endpoint you own, and Elva delivers event notifications to it as JSON POST requests as activity occurs on your MCP server. Your endpoint acknowledges with a 2xx , and whatever automation you attach — a chat message, a ticket, a row in the warehouse — runs from there. G[Elva gateway]; G-->|JSON POST| W[Your webhook endpoint]; W-->S[Slack, PagerDuty, SIEM, warehouse]; classDef accent fill:#ffffff,stroke:#ffffff,color:#15152A; class W accent;" role="button" tabindex="0" title="Click to zoom" data-mermaid-state="ready"> #mermaid-diagram--rhq-{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;fill:#000000;}@keyframes edge-animation-frame{from{stroke-dashoffset:0;}}@keyframes dash{to{stroke-dashoffset:0;}}#mermaid-diagram--rhq- .edge-animation-slow{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 50s linear infinite;stroke-linecap:round;}#mermaid-diagram--rhq- .edge-animation-fast{stroke-dasharray:9,5!important;stroke-dashoffset:900;animation:dash 20s linear infinite;stroke-linecap:round;}#mermaid-diagram--rhq- .error-icon{fill:#552222;}#mermaid-diagram--rhq- .error-text{fill:#552222;stroke:#552222;}#mermaid-diagram--rhq- .edge-thickness-normal{stroke-width:1px;}#mermaid-diagram--rhq- .edge-thickness-thick{stroke-width:3.5px;}#mermaid-diagram--rhq- .edge-pattern-solid{stroke-dasharray:0;}#mermaid-diagram--rhq- .edge-thickness-invisible{stroke-width:0;fill:none;}#mermaid-diagram--rhq- .edge-pattern-dashed{stroke-dasharray:3;}#mermaid-diagram--rhq- .edge-pattern-dotted{stroke-dasharray:2;}#mermaid-diagram--rhq- .marker{fill:#444444;stroke:#444444;}#mermaid-diagram--rhq- .marker.cross{stroke:#444444;}#mermaid-diagram--rhq- svg{font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:16px;}#mermaid-diagram--rhq- p{margin:0;}#mermaid-diagram--rhq- .label{font-family:"trebuchet ms",verdana,arial,sans-serif;color:#000000;}#mermaid-diagram--rhq- .cluster-label text{fill:#000000;}#mermaid-diagram--rhq- .cluster-label span{color:#000000;}#mermaid-diagram--rhq- .cluster-label span p{background-color:transparent;}#mermaid-diagram--rhq- .label text,#mermaid-diagram--rhq- span{fill:#000000;color:#000000;}#mermaid-diagram--rhq- .node rect,#mermaid-diagram--rhq- .node circle,#mermaid-diagram--rhq- .node ellipse,#mermaid-diagram--rhq- .node polygon,#mermaid-diagram--rhq- .node path{fill:#ECECFF;stroke:#9370DB;stroke-width:1px;}#mermaid-diagram--rhq- .rough-node .label text,#mermaid-diagram--rhq- .node .label text,#mermaid-diagram--rhq- .image-shape .label,#mermaid-diagram--rhq- .icon-shape .label{text-anchor:middle;}#mermaid-diagram--rhq- .node .katex path{fill:#000;stroke:#000;stroke-width:1px;}#mermaid-diagram--rhq- .rough-node .label,#mermaid-diagram--rhq- .node .label,#mermaid-diagram--rhq- .image-shape .label,#mermaid-diagram--rhq- .icon-shape .label{text-align:center;}#mermaid-diagram--rhq- .node.clickable{cursor:pointer;}#mermaid-diagram--rhq- .root .anchor path{fill:#444444!important;stroke-width:0;stroke:#444444;}#mermaid-diagram--rhq- .arrowheadPath{fill:#333333;}#mermaid-diagram--rhq- .edgePath .path{stroke:#444444;stroke-width:2.0px;}#mermaid-diagram--rhq- .flowchart-link{stroke:#444444;fill:none;}#mermaid-diagram--rhq- .edgeLabel{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rhq- .edgeLabel p{background-color:rgba(232,232,232, 0.8);}#mermaid-diagram--rhq- .edgeLabel rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rhq- .labelBkg{background-color:rgba(232, 232, 232, 0.5);}#mermaid-diagram--rhq- .cluster rect{fill:#ffffde;stroke:#aaaa33;stroke-width:1px;}#mermaid-diagram--rhq- .cluster text{fill:#000000;}#mermaid-diagram--rhq- .cluster span{color:#000000;}#mermaid-diagram--rhq- div.mermaidTooltip{position:absolute;text-align:center;max-width:200px;padding:2px;font-family:"trebuchet ms",verdana,arial,sans-serif;font-size:12px;background:hsl(80, 100%, 96.2745098039%);border:1px solid #aaaa33;border-radius:2px;pointer-events:none;z-index:100;}#mermaid-diagram--rhq- .flowchartTitleText{text-anchor:middle;font-size:18px;fill:#000000;}#mermaid-diagram--rhq- rect.text{fill:none;stroke-width:0;}#mermaid-diagram--rhq- .icon-shape,#mermaid-diagram--rhq- .image-shape{background-color:rgba(232,232,232, 0.8);text-align:center;}#mermaid-diagram--rhq- .icon-shape p,#mermaid-diagram--rhq- .image-shape p{background-color:rgba(232,232,232, 0.8);padding:2px;}#mermaid-diagram--rhq- .icon-shape .label rect,#mermaid-diagram--rhq- .image-shape .label rect{opacity:0.5;background-color:rgba(232,232,232, 0.8);fill:rgba(232,232,232, 0.8);}#mermaid-diagram--rhq- .label-icon{display:inline-block;height:1em;overflow:visible;vertical-align:-0.125em;}#mermaid-diagram--rhq- .node .label-icon path{fill:currentColor;stroke:revert;stroke-width:revert;}#mermaid-diagram--rhq- :root{--mermaid-font-family:"trebuchet ms",verdana,arial,sans-serif;}#mermaid-diagram--rhq- .accent>*{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rhq- .accent span{fill:#ffffff!important;stroke:#ffffff!important;color:#15152A!important;}#mermaid-diagram--rhq- .accent tspan{fill:#15152A!important;} JSON POST Agent activity on your MCP server Elva gateway Your webhook endpoint Slack, PagerDuty, SIEM, warehouse • [Workspace logs](https://docs.getelva.ai/admin-and-management/workspace-logs.md): Agents get logged by the gateway. Humans get logged by the workspace. Workspace logs are the admin’s audit trail: a structured record of the actions that shape your workspace — who connected which repo, what scanned and when, and which security-relevant events fired — so “who did that?” is a lookup, not an investigation. What gets recorded Every entry is a typed event, captured automatically as people work. The record covers the workspace’s whole administrative surface: Title Description Category Events Connections GitHub account connected via OAuth; repositories connected and disconnected Scans Every scan's lifecycle: started, succeeded, or failed Security signals Failed OAuth callbacks and detection of a revoked GitHub token — the early warnings that access is broken or was withdrawn Account lifecycle Account deletion, so offboarding leaves a record Every event, fully attributed A log line is only as useful as its context, so each entry carries the who, what, where, and from-where: Title Description Field What it tells you Actor The workspace user behind the action Event type The typed action, filterable — no free-text archaeology Target repository Which connected repo the event touched, when one is involved Timestamp When it happened, for timeline reconstruction IP & user agent The request context — where the action came from and through what Details Event-specific metadata attached to the entry Workspace log entries are retained for 90 days and then expire automatically — long enough for audits, reviews, and debugging, without accumulating an unbounded archive. What admins do with them Audit. “Who connected the payments monorepo, and when?” is one filtered query — with the actor, the IP, and the timestamp attached. Security review. A revoked-token detection or a burst of failed OAuth callbacks is exactly the kind of quiet signal that predicts a louder incident. Here it is on the record, not lost in a server log. Debugging. Scans started failing Tuesday? The log shows every scan’s outcome in sequence, next to whatever changed around it. The full observability picture Workspace logs complete a three-layer story, each layer answering a different question: MCP insights & logs — what agents did, per server, call by call. Workspace logs — what people did, across the workspace. MCP webhooks — either stream, pushed into your own systems as it happens. This is what management-grade tooling means in practice: every actor in your workspace — human or agent — leaves a trail you can query, and none of it required setup. Where to go next MCP webhooks Push MCP activity into Slack, your SIEM, or your warehouse instead of polling for it. MCP insights & logs The agent-side record: per-agent activity, per-tool health, and the call-by-call log.