How to Design OpenAPI Contracts That Guide AI Agents
What you will learn
- How to enrich an OpenAPI contract for progressive tool discovery.
- How to declare effects, intent, and planning facts for AI agents.
- How to model business state and human-established facts.
- How to audit, simulate, and serve the capability graph.
- How to verify agent behavior in VS Code.
Model Context Protocol (MCP) servers give AI agents access to real systems. When an MCP server exposes every operation of an Application Programming Interface (API) at once, the agent spends its limited context on tool definitions it never uses. It picks the wrong tool, or it claims a capability is unavailable when the right tool exists. HAPI turns an OpenAPI 3.x contract into an MCP server. The HAPI Capability Graph (HCG) adds a deterministic map of business state to that server. OrcA is a Visual Studio Code (VS Code) extension and a specialised harness for MCP and API work. It loads tools progressively, shows the capability graph in a Context tab, and records every exchange in a Traffic view. Clooney, an AI teammate built on Clawne Me, relies on the same harness pattern to work with your APIs.
This guide shows you how to enrich an existing OpenAPI contract so that HAPI, OrcA, and Clooney find the right tool at the right moment without bloating the context. You write discoverable operation metadata, declare effects and intent, and model business state with planning facts. You then declare the facts that only people can establish, describe failure outcomes, audit and simulate the graph, serve it with progressive discovery, and verify the behavior in OrcA. At the end of this guide, you have a contract that produces focused tool discovery, explicit plans, and clear clarification questions for any MCP client.
Key Takeaways
This section answers the main question of this guide in five statements.
- Sending every tool definition upfront wastes context and lowers tool-selection accuracy; progressive discovery loads tools as the conversation needs them.
- Verb-first
operationIdvalues and summaries in the language of your users drive tool search. x-hapi-intent,x-hapi-effects, andx-readOnlyHintcontrol ranking and confirmations.x-hapi-planning,x-hapi-client-facts, andx-hapi-outcometurn the contract into plans that ask for missing choices instead of guessing them.hapi graph auditexits with code1on gaps, so you can gate contract changes in CI.
Prerequisites
Before you begin, you need:
- A valid OpenAPI 3.x contract for an API you own or maintain.
- The HAPI Command Line Interface (CLI) installed with the Capability Graph plugin. Run
hapi --versionandhapi graph --helpto confirm both commands respond. - VS Code with the OrcA extension installed.
- A chat model configured in OrcA, either through an API key for a supported provider or through a VS Code language model.
- Working knowledge of YAML and of OpenAPI paths, operations, and responses.
The examples use a fictional clinic appointments API with the operations listSpecialties, searchProfessionals, getAvailability, bookAppointment, listPatientAppointments, cancelAppointment, and rescheduleAppointment. Replace the names and facts with the ones from your own domain.
Understand How OrcA Loads Tools Progressively
This section explains how OrcA decides which tool definitions reach the model, so that each metadata choice in the next sections has a clear purpose.
A Large Language Model (LLM) reads every tool definition you send with each request. Twenty operations with detailed request schemas can consume thousands of tokens before the user says a word, and tool selection accuracy drops as the list grows. OrcA avoids this cost with progressive tool discovery:
- Upfront tools stay small. OrcA sends a single
search_toolstool plus the tools a server marks as always loaded, such ascapability_contextandcapability_plan. - A compact catalog lists what exists. The
search_toolsdescription names every tool that is not loaded yet, with a one-line purpose for small catalogs. The model knows a booking tool exists before it needs it. - Tools load as the conversation moves. Before the model answers each message, OrcA searches your server with that message and loads the matching tools. The model can also call
search_toolswith a query or with exact tool names. - The capability graph adds context. On servers with capability planning, OrcA asks
capability_contextwith each message, shows the result in the Context tab, and loads the tools that the result points to. - Loaded tools stay loaded. OrcA appends discovered tools to the conversation and never reorders them, so provider prompt caches keep working. New Chat clears them.
Your contract feeds every step of this flow. Operation names and summaries drive search, intent and effects drive ranking and confirmation, and planning facts drive context and plans. Contracts with weak metadata still work, but the agent searches longer and asks fewer precise questions.
Write Discoverable Operation Names and Summaries
This section shows you how to write operation identifiers, summaries, and descriptions that search ranks correctly and that fit in the compact catalog.
HAPI search matches tool names, descriptions, and arguments. OrcA shows the first sentence of each description in the catalog, truncated to about 80 characters. Write each operation for both readers: the search index and the model.
-
Give every operation a stable, verb-first
operationId.paths:
/appointments:
post:
operationId: bookAppointmentThe
operationIdbecomes the tool name. Stable names keep conversations, saved Traffic sessions, and plans valid across releases. -
Start each
summarywith the action and the business object in the language your users write in.summary: Book an appointment for the patient
description: |
Books a confirmed appointment in the selected professional's free slot.
Use the `slotId` returned by getAvailability; a constructed value returns `400`.The first sentence of the description becomes the catalog line. Keep it short, specific, and free of internal jargon.
-
Describe every parameter and request property with the source of its value.
parameters:
- name: professionalId
in: query
required: true
description: Identifier from a searchProfessionals result row chosen by the patient.
schema:
type: stringParameter descriptions tell the model where a value comes from, which prevents invented identifiers.
Search in HAPI matches words, not meaning across languages. A contract written in Spanish does not match an English request such as "book an appointment" through search alone. Write summaries in the language of your users, or add the user-facing terms to the description. OrcA's catalog of tool names reduces the impact, but focused wording still produces better rankings.
Declare Intent, Effects, and Tool Hints
This section shows you how to tell the graph when an operation is the right choice, what it changes, and how MCP clients such as OrcA decide when to ask for confirmation.
-
Add
x-hapi-capabilityandx-hapi-intentto every operation.x-hapi-capability:
- Healthcare/Appointments/Booking
x-hapi-intent:
use-when:
- The patient selected a professional and a free slot and confirmed the details.
avoid-when:
- The patient only wants to see free slots or existing appointments.x-hapi-capabilityplaces the operation in a business taxonomy.use-whenandavoid-whengive the graph the evidence it needs to separate similar operations, such as booking and rescheduling. -
Add
x-hapi-effectsandx-hapi-prerequisites.x-hapi-effects:
mode: create
side-effecting: true
destructive: false
idempotent: false
requires-confirmation: true
x-hapi-prerequisites:
- The patient identity, the professional, and the slot must be verified.The graph uses effects to add gates such as
mutation-confirmation. Prerequisites explain readiness to people and to the model. They do not create machine state; planning facts do. -
Set MCP tool hints explicitly when the HTTP method does not describe the behavior.
/professionals/search:
post:
operationId: searchProfessionals
x-readOnlyHint: true
x-destructiveHint: false
x-idempotentHint: trueHAPI derives tool annotations from the
x-readOnlyHint,x-destructiveHint,x-idempotentHint, andx-openWorldHintextensions. Without them, HAPI marksGEToperations as read-only and everyPOST,PUT,PATCH, andDELETEoperation as destructive. OrcA's default confirmation policy asks before every tool that is not read-only, so a search implemented asPOSTasks for confirmation on every call unless you setx-readOnlyHint: true.
Model Business State with Planning Facts
This section shows you how to describe what each operation requires and changes, so that capability_context and capability_plan return useful goals and routes.
A fact is a lowercase predicate that names verified business state, such as professional.selected or appointment.booked. A transition is an operation that requires some facts, produces others, and optionally removes facts. The planner searches transitions from the facts that are true now to the goal facts the user wants.
-
List the business states of your domain before you write metadata.
Operation Requires Produces Removes searchProfessionalsnone professionals.consultednone getAvailabilityprofessional.selectedavailability.consultednone bookAppointmentpatient.identity.verified,professional.selected,slot.selected,appointment.details.confirmedappointment.bookednone cancelAppointmentpatient.identity.verified,appointment.selected,cancellation.confirmedappointment.cancelledappointment.bookedThe table exposes gaps early. A mutation that needs a choice must have an operation or a person that establishes that choice.
-
Add
x-hapi-planningto each operation.x-hapi-planning:
requires:
- predicate: patient.identity.verified
- predicate: professional.selected
- predicate: slot.selected
- predicate: appointment.details.confirmed
produces:
- predicate: appointment.booked
cost: 1Every planning entry needs at least one produced fact and a finite, nonnegative
cost. A lower cost makes the planner prefer that transition when several routes exist. -
Keep searches separate from selections.
/professionals/search:
post:
operationId: searchProfessionals
x-hapi-planning:
produces:
- predicate: professionals.consulted
cost: 1A search produces
professionals.consulted. It never producesprofessional.selected, because a person makes that choice. This boundary makes the plan pause and ask the user instead of picking the first result.
Follow these rules for every fact:
- Use business state, such as
appointment.booked, not commands such asbookAppointment. - Avoid wishes and guesses, such as
patient.wants.appointmentor a date the user did not confirm. - Add a cross-domain requirement only when a real business rule demands it.
Declare Facts That Only People Can Establish
This section shows you how to document the facts that your API never produces, so that the planner and OrcA know who must establish them.
Selections, confirmations, and identity checks happen in the conversation, not in the API. Without a declaration, the graph treats these facts as orphan requirements and reports booking goals as unreachable.
-
Compile and audit the contract.
$ hapi graph compile ./clinic.openapi.yaml --out clinic.graph.json
$ hapi graph audit clinic.graph.jsonThe audit output lists the gaps:
Orphan requirements (required, never produced, not client-verified):
✗ appointment.details.confirmed required by bookAppointment
✗ professional.selected required by bookAppointment, getAvailability
✗ slot.selected required by bookAppointment, rescheduleAppointment
...
Reachability
✗ appointment.booked: clarification-required (goal-unreachable, missing-planning-facts)
Result: gaps found -
Declare the client facts at the root of the contract.
x-hapi-client-facts:
- predicate: patient.identity.verified
description: The phone number comes from the chat channel, not from typed text.
- predicate: professional.selected
description: The patient picked one professional from the search results.
- predicate: slot.selected
description: The patient picked one free time slot.
- predicate: appointment.details.confirmed
description: The patient confirmed the appointment summary.Each description states who establishes the fact and how. The model reads these descriptions in context results and asks the right question at the right step.
-
Compile and audit again.
$ hapi graph compile ./clinic.openapi.yaml --out clinic.graph.json
$ hapi graph audit clinic.graph.jsonThe audit now lists the facts under Client-verified facts, every outcome shows
planned, and the result isclean. The command exits with code1when gaps remain, so you can add it to a Continuous Integration (CI) pipeline.
Describe Failure Outcomes for Re-Planning
This section shows you how to declare what a failed response means for business state, so that a client can re-plan instead of retrying blindly.
-
Add
x-hapi-outcometo each non-success response that forces a new decision.responses:
"201":
description: Appointment booked.
"409":
description: The slot was taken by another patient.
x-hapi-outcome:
produces:
- predicate: slot.unavailable
removes:
- predicate: slot.selectedThe status key accepts a code, an
NXXrange, ordefault, but never a2xxstatus. The operation must also declarex-hapi-planning. -
Describe the next step in the response description.
A clear description, such as "The slot was taken by another patient; ask the patient to pick another slot," turns a raw error into a question the agent can ask. The planner never plans through an outcome, but plan steps list outcomes so that clients know which alternatives exist.
Audit, Simulate, and Visualize the Graph
This section shows you how to test plans before any agent calls your API.
-
Simulate a goal without verified facts.
$ hapi graph simulate clinic.graph.json --initial-fact patient.identity.verified --goal-fact appointment.bookedThe output reports
Outcome: clarification-requiredwith the diagnosticmissing-planning-facts. This result is correct: the patient has not chosen a professional or a slot yet. -
Simulate the same goal with every required fact and gate.
$ hapi graph simulate clinic.graph.json \
--initial-fact patient.identity.verified \
--initial-fact professional.selected \
--initial-fact slot.selected \
--initial-fact appointment.details.confirmed \
--goal-fact appointment.booked \
--satisfied-gate mutation-confirmation \
--eligible-operation bookAppointmentThe output reports
Outcome: plannedwith one step,operation:bookAppointment. The--eligible-operationoption simulates an authorized principal. Without it, the plan reports the unsatisfiedoperation-authorizationgate. -
Generate a visual review for domain experts.
$ hapi graph visualize clinic.graph.json \
--initial-fact patient.identity.verified \
--goal-fact appointment.booked \
--out clinic-flow.htmlOpen
clinic-flow.htmlin a browser. The Business State Flow shows which facts each operation requires, produces, and removes. Review it with the people who own the business process; an unexpected gap is contract feedback, not a planner error.
Serve the API with Progressive Discovery
This section shows you how to choose the HAPI flags that match the level of guidance you need.
-
Serve with deferred tool search only.
$ hapi serve --specs ./clinic.openapi.yaml --deferred-tool-search --port 3000HAPI marks operation tools as deferred and adds a
tool_searchtool. OrcA detects it and enables progressive discovery. Use this level when you want smaller context without planning metadata. -
Serve with the capability graph and planning.
$ hapi serve --specs ./clinic.openapi.yaml --capability-graph --capability-planning --port 3000--capability-graphcompiles the graph and implies deferred search with graph-aware ranking.--capability-planningadds the read-onlycapability_contextandcapability_plantools. Neither tool calls your API, stores state, or grants authorization. -
Serve an existing backend in headless mode.
$ hapi serve --specs ./clinic.openapi.yaml --headless --url https://api.example.com --capability-graph --capability-planning --port 3000Headless mode exposes only the MCP endpoint and forwards calls to the backend at
--url. Add--dev --capability-traceduring development to emit redacted graph diagnostics.
Without these flags, HAPI serves every tool upfront, as before. OrcA then sends every definition to the model unless you set orca.chat.toolDiscovery to always, which applies OrcA's local search to any server.
Connect the Server in OrcA
This section shows you how to add your server to OrcA and confirm that progressive discovery and the capability graph are active.
-
Open the MCP Servers view in the OrcA activity bar.
-
Add the server.
- For a contract in your workspace, start it with HAPI from OrcA so that it appears as a local run.
- For a running server, add an external server with a name such as
clinic, the URLhttp://localhost:3000/mcp, and any required headers. OrcA stores header values in the VS Code secret storage.
-
Connect the server and hover over it.
The tooltip shows a Discovery line, for example "Progressive tool discovery: tool_search (8 of 11 tools deferred) · Capability graph: capability_context, capability_plan". Deferred tools carry a
deferredmarker in the tool list. -
Open the Harness tab in the OrcA view.
The preview shows the tokens of the tools sent upfront compared with all definitions, per server. Use this number to measure the context you save.
-
Review the discovery settings.
Setting Default Purpose orca.chat.toolDiscoveryautoautodefers tools on servers with search,alwayssearches every server,offsends every tool.orca.chat.toolSearchLimit5Maximum tools returned per server for each search. orca.chat.toolPrefetchtrueSearches and asks capability_contextwith each message before the model answers.orca.chat.confirmToolsmutatingAsks before tools that are not read-only.
Verify the Behavior in Chat, Context, and Traffic
This section shows you how to confirm that the agent discovers tools as the conversation progresses and that plans ask for the right facts.
-
Start a multi-step conversation in the Chat tab.
Find a pediatrician in Springfield.A card titled Tools loaded for your request lists the tools OrcA loaded before the model answered, such as
searchProfessionals. -
Move the conversation to the next step.
Book the first one for next Tuesday afternoon.OrcA loads
getAvailabilityandbookAppointmentfor this message. The model asks you to choose a slot and to confirm the details, because the plan requiresslot.selectedandappointment.details.confirmed. OrcA shows an inline confirmation before the booking call because the tool is not read-only. -
Open the Context tab.
Under From Chat, each message lists the candidate operations, goal facts, required facts, and gates. Select Plan This Goal on
appointment.booked, enter the facts you verified, one per line, and select Create Plan. The plan lists the steps, the missing facts, and the unsatisfied gates. -
Open the Traffic view.
Each model round, search, context request, and tool call appears with its latency, size, tokens, and cost. Select a tool call to see the model round that caused it. Use Show in Traffic in the Context tab to jump to the exact
capability_contextexchange. -
Check the Activity tab.
The tab records connections, new chats, and failures with a plain explanation of which service failed and why.
Troubleshoot Common Discovery Problems
This section maps common symptoms to the contract change that fixes them.
| Symptom | Likely cause | Fix |
|---|---|---|
| The model says it has no tool for an action. | The operation summary does not match the user's words or language. | Rewrite the summary and description with user-facing terms, and confirm the tool appears in the catalog. |
| Search returns unrelated tools. | Generic summaries such as "Process request". | Use verb-first summaries and specific use-when statements. |
| Every search call asks for confirmation. | A read-only operation uses POST without hints. | Add x-readOnlyHint: true and x-destructiveHint: false. |
Plans return clarification-required for every goal. | Orphan requirements. | Run hapi graph audit and declare x-hapi-client-facts. |
| The agent picks the first search result. | A search produces a selection fact. | Produce a consultation fact and declare the selection as a client fact. |
| The agent retries a failed booking. | The failure response has no outcome. | Add x-hapi-outcome and a description that names the next question. |
Frequently Asked Questions
This section answers the questions readers ask most often about this topic.
What Is MCP Context Bloat, and How Do I Avoid It?
Context bloat happens when an MCP server sends every tool definition with every request, so the model spends its context on tools it never uses and picks the wrong one more often. Serve the contract with --capability-graph or --deferred-tool-search, and let a harness such as OrcA load tools progressively.
What Is Progressive Tool Discovery?
Progressive tool discovery sends a small search tool and a few always-loaded tools instead of the full catalog. OrcA loads matching tools before the model answers each message, lists the names of the remaining tools so the model knows they exist, and appends discovered tools without reordering them, which keeps prompt caches valid.
What Are the X-Hapi Extensions in OpenAPI?
They are OpenAPI extensions that HAPI compiles into its capability graph: x-hapi-capability and x-hapi-intent for discovery, x-hapi-effects and x-hapi-prerequisites for behavior, x-hapi-planning for state transitions, x-hapi-client-facts for facts people establish, x-hapi-outcome for failure responses, and x-hapi-event for webhooks.
Why Does capability_plan Always Return Clarification-Required?
Usually because some required facts are never produced by an operation and are not declared as client facts. Run hapi graph audit to list these orphan requirements, then declare selections, confirmations, and identity checks in x-hapi-client-facts.
Why Does Every Search Tool Ask for Confirmation?
HAPI marks every POST, PUT, PATCH, and DELETE operation as destructive unless the contract sets tool hints, and clients such as OrcA ask before any tool that is not read-only. Add x-readOnlyHint: true and x-destructiveHint: false to read-only searches that use POST.
Does HAPI Tool Search Work Across Languages?
No. HAPI search matches words in tool names, descriptions, and arguments. Write summaries in the language of your users, or add their terms to descriptions; OrcA's catalog of tool names reduces, but does not remove, the impact of a language mismatch.
Conclusion
You enriched an OpenAPI contract so that HAPI, OrcA, and Clooney find the right tool at the right moment. Verb-first operations and precise descriptions drive progressive discovery. Intent, effects, and tool hints separate similar operations and keep confirmations meaningful. Planning facts, client facts, and response outcomes turn the contract into a capability graph that asks for missing choices instead of guessing them. You audited and simulated the graph, served it with progressive discovery, and verified the behavior in OrcA's Chat, Context, Traffic, and Activity views.
Apply the same process to the next API in your portfolio. Run hapi graph audit in your CI pipeline to catch new gaps, and compare the token preview in the Harness tab before and after each change to measure the context you save.
