In this experiment, we asked Claude Code to build a Java Swing application that manages Salesforce Account records with full CRUD operations and a GUI. What should be a straightforward data integration task turned into a debugging marathon.
This blog describes that experience and explores how the same project works using CData Code Assist MCP, a locally installed MCP server, for schema exploration and CData JDBC drivers for runtime connectivity. CData Code Assist MCP connects AI coding tools like Claude Code to data sources, giving them direct access to schemas, metadata, and live data during development. Instead of guessing at field names or valid values, the AI can ask the database what it needs to know.
The challenge
We want to build a Java app using natural language with LLM-assisted development. Our first user prompt reads: "Create a Java application with a GUI that reads account information from Salesforce using Salesforce's API. Add insert, update, and delete features."
Simple enough, right? Now, let's see how it goes.
Approach 1: Building with Salesforce REST API
Claude Code maps out a clean architecture
For this experiment, we use Java version 11.0.28 and give Claude Code a simple prompt without specifying how to connect to Salesforce. We don't mention REST API, SOAP, or any particular authentication method.
Claude Code devises its own well-structured plan:
12 Java files across auth, API, and UI packages
OAuth 2.0 Web Flow authentication
Apache HttpClient for REST calls
Gson for JSON serialization
Swing-based GUI with table view and forms
The architecture looks clean. However, the problems come during implementation.
Authentication becomes a roadblock
The first implementation attempts to use standard OAuth 2.0. However, Salesforce rejects it outright.
The problem? Our first attempt times out while waiting for the authentication callback. The fix? We need to change the server binding from 'all interfaces' to localhost '127.0.0.1'. The second attempt produces an error message about a missing required code challenge.
Finally, Salesforce refuses to proceed without PKCE (Proof Key for Code Exchange). This isn't optional. The API actively blocks the simpler OAuth flow because modern Salesforce orgs enforce PKCE as a security requirement.
The fix requires implementing full PKCE support:
Generate cryptographically random code verifier
Create SHA-256 hashed code challenge
Add both parameters to authorization flow
Include code verifier in token exchange
This authentication code alone consumes roughly 100 lines of the implementation.
The AI resorts to guesswork for picklist values
Once authenticated, we try creating an Account record, but it results in immediate failure.
The response from our coding assistant? "The country I input is not valid. Please select one from the list."
The Salesforce instance has State/Country picklists enabled. Claude Code doesn’t inherently know how to discover valid values. Without access to Salesforce's schema metadata, the AI can't query which values are configured in this organization. The alternative would be uploading comprehensive API documentation to the AI, but even then, documentation describes standard fields, not organisation-specific picklist configurations. Instead of using known valid values, it simply guesses:
private static final String[] COUNTRIES = {
"", "United States", "Canada", "United Kingdom", "Australia",
"Germany", "France", "Japan", "China", "India", "Brazil"...
};
The same issue applies to States. Our coding assistant tries another hardcoded array based on guessing.
This approach is deeply flawed, because it is:
Incomplete - Misses many valid values configured in this Salesforce instance
Fragile - If Salesforce's configured values differ from the guesses, records fail to save
Not discoverable - The AI has no visibility into what values are valid
Boilerplate code piles up
The SalesforceClient.java file needs to handle SOQL query construction and URL encoding, HTTP request/response lifecycle, authorization header injection, JSON parsing and error handling, and API versioning (/services/data/v59.0/).
Simple operations like "get all accounts" require 15-20 lines of code each.
The final tally
After multiple build-fix cycles, the application works. But the experience proves painful:
Metric | Count |
Total files created | 12 |
Lines for OAuth + PKCE | ~100 |
Lines for REST client | ~150 |
Build-test-fix cycles | 5+ |
Hardcoded assumptions | Multiple arrays |
Estimated developer time | ~2 hours |
Approach 2: Building with CData Code Assist MCP and JDBC
Before writing any code, Claude Code can use CData Code Assist MCP to learn about the Salesforce schema. The connection comes with embedded instructions to guide Claude Code through the best practice steps for schema exploration without any user intervention or prompting required.
Note: We still don't prompt the underlying LLM of Claude Code on how to connect to Salesforce, but we do configure Code Assist MCP for Salesforce, which guides the LLM to use the CData JDBC Driver to work with Salesforce.
The AI explores the schema before writing code. When planning Account related CRUD operations, Claude Code has access to the underlying data model for the Salesforce connection that is used at run time. During planning, Claude Code recognizes it needs to discover the appropriate Account object. Instead of guessing the Salesforce schema and forcing the developer to manually intervene and dig through API documentation, Claude Code queries the schema directly using a specialized MCP tool (get_tables).
This returns all Salesforce objects related to Account. While Salesforce calls these "objects," CData's SQL interface presents them as "tables," giving Claude Code a familiar database paradigm to work with. The results include Account, AccountContactRelation, AccountContactRole, AccountFeed, AccountHistory, and other related objects.
After identifying the correct object for Account CRUD operations, Claude Code needs to understand the field structure so it can write correct SQL queries that work the first time. It explores this through another specialized MCP tool (get_columns).
This returns important metadata for all fields within the Account object. Salesforce calls these "fields," but CData presents them as "columns" for SQL compatibility. The metadata includes details like Id (VARCHAR, primary key), Name (VARCHAR), BillingState (VARCHAR), BillingCountry (VARCHAR), Industry (VARCHAR), Phone (VARCHAR), and other fields with their data types and labels.
Now that Claude Code understands the underlying structure for the Account object and related fields, it can build optimized queries before writing any code to explore the appropriate values to include in the application. This eliminates the issues experienced with Country in the REST API experiment, because the correct values, in the correct format, are included from the start. In the REST API experiment, Claude Code had to guess at picklist values when it needed them during planning, and even uploading API documentation wouldn't help, since docs describe standard fields, not this org's specific configurations. With Code Assist MCP, Claude Code pulls the correct values the first time.
Claude Code automatically generates a query to retrieve valid picklist values:
SELECT [PickList_Value], [PickList_Label], [PickList_IsActive]
FROM [PickListValues]
WHERE [TableName] = 'Account' AND [ColumnName] = 'BillingCountryCode'
This query returns the exact values configured in this Salesforce org: AF (Afghanistan), AU (Australia), CA (Canada), US (United States), and all other valid country codes with their labels and active status.
Configuration replaces custom code
The REST API approach requires approximately 100+ lines of code to generate PKCE code verifier and challenge, build authorization URL with all parameters, start local HTTP server for callback, handle browser redirect, exchange code for tokens, and manage token refresh.
The CData approach uses UI-based configuration instead. It provides configuration UIs for both development and runtime.
Both CData Code Assist for Salesforce and CData Salesforce JDBC driver support the same authentication options (OAuth, OAuthPKCE, JWT, enterprise SSO) through dropdowns and fields, not code.
The Code Assist MCP UI generates config for the AI coding tool, while the JDBC Driver UI generates connection strings for the runtime application.
The complexity that consumes 100+ lines and multiple debug cycles becomes a configuration choice in both phases.
Comparing the two approaches
Aspect | Salesforce REST API | Code Assist MCP + JDBC |
Salesforce Setup | Connected App with OAuth, callback URLs, scopes | None (username/password auth) |
Authentication Code | ~100 lines (OAuth + PKCE) | 0 lines (connection string) |
API Client Code | ~150 lines | ~30 lines |
Schema Discovery | Manual/documentation | Interactive MCP queries |
Picklist Values | Hardcoded arrays (guess and check) | Query metadata table |
Debug Cycles | 5+ iterations | Minimal (1-2) |
Estimated Dev Time | ~2 hours | ~15 minutes |
Why this matters for long-term maintenance
The CData virtualization layer provides maintenance advantages that compound over time.
Handling API version changes: Salesforce deprecates API versions regularly. REST API code contains hardcoded version strings (>/v59.0/). CData handles versioning internally, so developers update the driver, not the code.
Adapting to schema evolution: When Salesforce admins modify picklists or add fields, hardcoded arrays break silently. CData queries live metadata, so the application always knows the current valid values.
Keeping up with authentication requirements: Salesforce continues to tighten authentication requirements, moving from OAuth to PKCE to MFA. Custom auth code becomes technical debt. CData absorbs protocol changes in driver updates.
Protecting against breaking changes: REST API code parsing JSON directly remains exposed to response format changes. The virtualization layer isolates SQL-based code from these changes.
Going beyond CRUD: Complex queries made simple
The Account Manager represents a simple single-table app. More complex scenarios reveal even greater value.
Consider this prompt: "Build a sales pipeline dashboard with account details and contact information."
With CData Code Assist MCP, the AI discovers foreign keys and builds join queries interactively:
SELECT a.[Name] AS AccountName,
o.[Name] AS OpportunityName,
o.[StageName],
o.[Amount],
c.[Name] AS ContactName,
c.[Email]
FROM [Account] a
INNER JOIN [Opportunity] o ON a.[Id] = o.[AccountId]
LEFT JOIN [Contact] c ON o.[ContactId] = c.[Id]
WHERE o.[IsClosed] = 0 AND o.[Amount] > 10000
ORDER BY o.[Amount] DESC
No guessing at field names. No manual JSON stitching. No multiple API roundtrips.
Key takeaways
AI-coding tools deliver power, but they're limited by what they can see. When Claude Code encounters Salesforce's REST API, it works blindly. It guesses at field names, authentication requirements, and valid values until errors reveal the truth.
CData Code Assist MCP changes this dynamic by giving the AI conversational access to schema metadata and live data during the planning phase. The JDBC driver then provides a familiar, standardized interface for the runtime implementation.
This simple Account Manager project demonstrates an 8x reduction in development time (2 hours vs 15 minutes). But the benefits extend beyond initial development. Developers get less code, less debugging, less frustration, reduced maintenance burden, and more time spent on features that matter.
When AI coding assistants can see the data structure, query metadata tables for valid values, and work with familiar SQL interfaces instead of complex REST APIs, the entire development experience transforms from a debugging marathon into a productive collaboration.
Supercharge your AI coding workflows with CData Code Assist MCP
CData Code Assist MCP connects AI coding tools to 350+ enterprise data sources, enabling schema exploration through the Model Context Protocol (MCP).
Download the free CData Code Assist MCP for Salesforce to see for yourself!
Explore CData Drivers and Connectors
Get blazing-fast access to live data with seamless connectivity from your data sources to the tools you use every day. Our standards-based connectors make data integration effortless – just point, click, and go.
Try them now