While thinking about how agents could build applications with Oracle, I started considering how those agents might test what they build.
An agent could generate an application that analyzes HTTP traffic, complete with controls for configuring requests, inspecting results, and reviewing logs. A developer would interact with the application through Oracle's UI.
But what if the agent could interact with that same application through MCP?
Both would use the same underlying functionality, with different interfaces suited to how they work. The agent could exercise the application programmatically during development, while the developer could inspect its behavior through a UI.
I think there's an interesting opportunity here to make Oracle applications accessible to both humans and agents, while giving agents a practical way to test the tools they generate.
Sharing Application Functionality
Most developer tools have functionality that can be separated from their presentation.
Consider an HTTP analyzer. Its core operations might include analyzing a request, retrieving the status of an analysis, and canceling an active operation.
I could describe those capabilities with a TypeScript interface:
interface HttpAnalyzer {
analyze(request: AnalysisRequest): Promise<AnalysisResult>;
getStatus(operationId: string): Promise<OperationStatus>;
cancel(operationId: string): Promise<void>;
}
The interface describes what the analyzer can do. Different clients can decide how to expose those operations.
An Oracle UI could provide forms for configuring requests, buttons for starting operations, and views for inspecting results. An MCP server could expose the operations as tools that an agent can invoke. Automated tests could call the interface directly.
All three would use the same implementation.
This would give developers several ways to package their applications:
- A standalone library used by other code.
- An Oracle application with a human interface.
- An MCP server exposing functionality to agents.
- An application supporting both human and agent interaction.
I like this flexibility because the application's functionality can evolve independently of its interaction methods.
An Optional MCP Adapter for Oracle
One way to support this would be an optional MCP adapter.
The adapter would expose selected application operations as MCP tools, using their schemas to describe inputs and outputs. The developer would decide which operations are available and provide their implementations.
For example, an HTTP analyzer might register an operation like this:
const analyzer = new HttpAnalyzerService();
mcp.expose({
name: 'analyze_http',
description: 'Analyze an HTTP request',
inputSchema: analysisRequestSchema,
execute: (request) => analyzer.analyze(request),
});
This is an illustrative API for the proposed adapter. I haven't implemented it in Oracle.
The idea is straightforward. The adapter takes care of exposing an operation through MCP, while the application handles the actual work.
The Oracle UI could use the same HttpAnalyzerService to execute requests and display results. Both interfaces would interact with the same service, keeping the implementation in one place.
The more interesting question is how much of this integration Oracle could make reusable across different applications.
Keeping Application Contracts Flexible
I see a tradeoff in how Oracle could define shared application interfaces.
A universal interface would give the MCP adapter a predictable structure to work with. Every application would expose the same set of capabilities, making integration relatively straightforward.
The downside is that developer tools have different interaction patterns.
A file analyzer might execute one operation and return a collection of results. A log monitor might continuously produce updates. A database inspector could support queries, navigation, and modifications.
Trying to fit all three into a single interface could introduce unnecessary complexity.
I would lean toward smaller, composable contracts that applications can implement as needed.
Oracle already has concepts that could provide a starting point:
- Actions for invoking application behavior.
- Observations for exposing application state.
- Events for communicating changes.
- Background work for operations that continue over time.
These concepts seem relevant to both human and agent interaction. The experiment would be determining which contracts can be reused directly and which need additional adaptation.
Ideally, a simple application could expose a single action, while a more complex tool could combine several capabilities.
Adapting Application Behavior to MCP
Sharing application functionality introduces some interesting questions about how different clients interact with it.
Long-running operations are one example.
An Oracle UI could start an analysis and subscribe to progress updates. As the operation runs, the UI could update a progress indicator and display intermediate results.
An MCP client might follow a different pattern:
- Invoke a tool to start the analysis.
- Receive an operation identifier.
- Retrieve the operation's status through subsequent calls.
- Fetch the results when the operation completes.
Other interaction patterns may be possible depending on the MCP client and supported protocol capabilities.
The adapter would need to translate between these patterns while preserving the application's actual execution state.
Cancellation presents another consideration. A client might request cancellation, but the underlying operation could still be running, particularly when an external process or service is involved.
The application needs to report what actually happened. The adapter should preserve that distinction when communicating with MCP clients.
Authorization also matters. Exposing an operation through MCP makes it available through another entry point, so the application needs appropriate permission checks and execution boundaries.
These details are where I expect much of the adapter's design work to happen. Mapping a function to an MCP tool looks relatively simple. Handling state, execution context, and lifecycle behavior across different clients is more interesting.
Giving Agents a Way to Test Their Own Tools
The testing possibilities are what originally made this idea appealing.
Suppose I ask an agent to build an Oracle application that analyzes a repository and produces a dependency graph.
The agent implements the analysis functionality and connects it to an Oracle UI. If the application also exposes its functionality through MCP, the agent can invoke the analyzer directly during development.
That creates three useful testing layers.
Testing Application Functionality
Automated tests can call the shared application interface directly.
For a repository analyzer, I could create a small directory structure with known dependencies and verify that the analyzer produces the expected graph.
These tests focus on the implementation's behavior, including how it handles invalid inputs and edge cases.
Testing the MCP Interface
The agent could invoke the application's MCP tools and inspect their responses.
This would exercise the adapter's tool registration, schema handling, input validation, and result serialization.
It would also give the agent a way to interact with the application it just generated.
I find that particularly useful because the agent could run the same operations that another agent would eventually invoke.
There are limits to what this verifies. The tests would still need to account for differences between the development environment and the environment where the MCP server runs.
Testing the Human Interface
The Oracle UI would have its own tests.
These would verify that controls display the correct state, submit the intended inputs, handle errors, and present results appropriately.
A successful MCP invocation establishes that the underlying operation works through that interface. UI testing still needs to verify the human interaction.
Sharing application functionality could reduce duplicated testing effort while making it easier to determine which layer is responsible when something fails.
Debugging Through Two Interfaces
Another possibility I find interesting is using the human interface to investigate problems encountered by agents.
Imagine an agent calls an MCP tool and receives an unexpected result.
If that tool is also exposed through an Oracle UI, I could open the application, provide the same inputs, and inspect the operation through a more detailed interface.
The UI could display execution state, intermediate results, structured output, and logs. Meanwhile, the agent could reproduce the same operation programmatically.
Both clients would exercise the same underlying implementation.
There would still be differences to investigate, including session state, transport behavior, permissions, and execution context. A shared implementation would give me a useful starting point for isolating those differences.
I could see this being helpful when developing MCP integrations, investigating agent failures, or testing tools intended for mixed human and agent workflows.
Starting With an MCP Inspector
I think an MCP inspector would be a good first experiment.
The application would connect to an MCP server, discover its available tools, and generate an interface that lets a developer invoke them.
For example, if an MCP server exposes a tool with a schema containing strings, numbers, booleans, and enumerations, Oracle could use that schema to generate the corresponding input controls.
The developer could enter values, invoke the tool, and inspect its response through Oracle's structured data controls.
This would create a practical utility while testing several parts of the proposed architecture.
It would also give me an opportunity to explore questions such as:
- How reliably can MCP tool schemas be translated into useful UI controls?
- Which input and output types need specialized presentation?
- How should the interface handle long-running operations?
- How much application functionality can be shared between the Oracle UI and MCP?
- Which parts of the implementation can be reused across different MCP servers?
I would start with basic JSON Schema types and expand the supported controls as the experiment reveals additional requirements.
There is also a useful recursive aspect to this idea.
If the inspector exposes its own testing operations through an MCP adapter, an agent could interact with the inspector programmatically. The agent could use it to discover and invoke tools on another MCP server.
An MCP inspector that agents can inspect through MCP. That seems appropriately circular for agent tooling.
The main thing I want to learn is whether this arrangement produces useful reusable contracts or introduces too much complexity between the application and its interfaces.
Keeping MCP Optional
I want Oracle applications to remain free to choose how their functionality is exposed.
A small local utility might only need a UI. An automation service might only need an MCP interface. Another application might benefit from both.
Making MCP support an optional adapter would preserve those choices.
It would also let Oracle's core application contracts evolve independently of MCP. The contracts could support different transports or integration patterns as new requirements emerge.
For applications that expose both interfaces, sharing the same underlying functionality would make it easier to keep their behavior consistent.
The adapter would provide reusable integration code, while developers would retain control over which operations are exposed and how they are authorized.
What I Want to Test Next
I haven't implemented the MCP adapter yet, so the immediate next step is to try this with a small application.
I'll start by defining a few operations that can be called directly, exposed through Oracle controls, and invoked through MCP. From there, I can see how much adapter code each operation requires and where the contracts become awkward.
I'm particularly interested in what happens when I introduce observable state and long-running operations. Those capabilities should reveal more about the design than a collection of simple functions.
If the approach works, it could give agents a practical way to build, exercise, and debug developer tools through the same functionality available to humans.
The question I want to answer is how much of that functionality can be shared before differences between the interfaces start shaping the application itself.
