Stop Building the Same Thing Twice
There’s a pattern quietly doubling your maintenance work. Every API you build for your app is being rebuilt from scratch for your AI…

Stop Building the Same Thing Twice
There’s a pattern quietly doubling your maintenance work. Every API you build for your app is being rebuilt from scratch for your AI assistant. Skill-First design fixes that — one handler, two consumers, no drift.
Picture this: your team just shipped a dashboard showing live revenue data. Three weeks of work. It calls a clean REST API, the data is right, the stakeholders are happy. Then, at the next sprint review, someone asks: “Can our AI assistant pull those same numbers?”
So you open a new file. You write a name, a description, an input schema — describing the exact same operation your API already handles. Different vocabulary, same logic, second file to maintain.
You’ve just built the same thing twice. And the clock for keeping them in sync has started ticking.
Why This Hurts More Than It Looks
The second copy feels cheap at first. It’s just a few lines of JSON, a description, a schema. But think about what happens six months later:
- A new field gets added to the API response. Someone forgets to update the AI tool definition. The assistant silently returns outdated data.
- Validation rules tighten on the backend. The AI tool keeps sending inputs that now get rejected. Nobody knows why the assistant keeps failing.
- An endpoint gets deprecated. The AI tool still advertises it. The assistant confidently calls something that no longer exists.
Every time your business logic changes, you have two places to update. You’ll remember to do both — until you don’t. That’s when the AI assistant starts giving wrong answers and nobody can immediately explain why.
The Skill-First Idea
The fix is simpler than it sounds. A capability is the atomic unit of your system. Not an endpoint. Not a tool definition. A capability — a named piece of logic that does one thing well. The REST endpoint and the AI tool definition are just two ways of reaching that same capability.
In practice, Skill-First means writing each capability as a self-contained handler, then exposing it through whatever interfaces your consumers need. Your web app calls it over REST. Your AI assistant calls it as a tool. Both run identical logic. Neither knows the other exists.

Fig 1 — Before: two separate descriptions of the same logic, drifting apart. After: one handler, two entry points.
The Pattern in Three Steps
You don’t need a framework to adopt this. The discipline has three steps, and you can apply them to your very next endpoint.
Step 1 — Write the handler once
This is your only source of truth. Pure logic. It takes typed input, runs the business rules, returns structured output. It has no idea whether a browser or an AI triggered it — and that’s the whole point.
// The one place the logic actually lives
async function getRevenueSummary(input) {
const data = await db.query(input.period, input.region);
return {
revenue: data.total,
orders: data.count,
fulfillmentRate: data.fulfilled / data.count,
period: input.period
};
}
If your handler contains the word req, res, or ctx, it knows too much. Keep HTTP out of the handler entirely.
Step 2 — Expose it over REST for your app
A thin adapter. It reads the HTTP request, calls the handler, sends back JSON. Your frontend never notices any difference — because there isn’t one.
// REST door — exactly what the web UI calls
app.get('/api/revenue/summary', async (req, res) => {
res.json(await getRevenueSummary(req.query));
});
Step 3 — Register it as an AI tool
Describe the same handler in the vocabulary your AI platform understands: a name, a plain-English description, an input schema. Point it at the same function. The assistant now reaches the same logic through a different door.
// Tool door — what the AI assistant calls
registerTool({
name: 'get_revenue_summary',
description: 'Revenue, order count, and fulfillment rate for a given period',
inputSchema: {
type: 'object',
properties: { period: { type: 'string' }, region: { type: 'string' } },
required: ['period']
},
handler: getRevenueSummary // the very same function
});
That’s the whole pattern. You wrote the logic once. You documented it once (in the tool description). When the business rules change, you touch one file. Both consumers stay correct because they share one source of truth.
Level Up: The Self-Describing Skill
Once the three-step discipline feels natural, the next move is to make each capability describe itself. Instead of registering the REST route and the tool definition in separate places, you define them once on a single object — and let each interface generate what it needs.
// A Skill object — one declaration, any number of consumers
const RevenueSummarySkill = {
id: 'get_revenue_summary',
description: 'Revenue, order count, and fulfillment rate for a given period',
input: { period: 'string', region: 'string' },
output: { revenue: 'number', orders: 'number', fulfillmentRate: 'number' },
execute: getRevenueSummary
};
// From this one object, generate:
// ✓ REST route — GET /api/revenue/summary
// ✓ MCP tool definition — registered with AI agent
// ✓ TypeScript client — typed hook for the frontend
At this stage, a single Skill definition can generate its REST route, its MCP tool definition, a GraphQL resolver, and a typed frontend hook — all from one source. That’s Skill-First Architecture in full. But you don’t need to start there.
Start with the three-step pattern on your next endpoint. You’ll get most of the benefit immediately. Migrate to self-describing Skills once the duplication starts to hurt — it’s a mechanical refactor, not a redesign.
Where to Start
Skill-First pays off the moment you have two consumers of the same logic. Building an app that will have both a UI and an AI assistant? Design for it from the first endpoint. Already have an API and about to add an assistant? Introduce the handler separation now — before you’ve written a pile of parallel tool definitions you’ll have to maintain forever.
Start with your next endpoint. Separate the handler from the HTTP adapter. Register the same handler as both a REST route and an AI tool. That’s it. When something changes six months from now, you change it in one place — and both consumers stay accurate without you thinking about it.
Try It on Your Next Endpoint
Pick one endpoint in your current project. Extract the business logic into a standalone handler function. Then register that same handler as both a REST route and an AI tool. That’s it — you’ve adopted Skill-First. Share what you build by tagging #SkillFirstAPI on LinkedIn or leaving a comment below.
Up next in this series → Skill-First gives your AI assistant access to the right capabilities. But once it can reach dozens or hundreds of them, how does it pick the right one for each question? Part 2 covers a hybrid tool search that delivers exactly the tools that matter — and gets smarter every time it’s used.
References & Further Reading
- MCP Tool Specification — official reference for tool names, schemas, and annotations
- MCP Draft Spec: Tools — includes the upcoming
x-mcp-headerand output schema additions - MCP Specification Repository — open-source, practitioner feedback welcome
- OpenAPI 3.1.0 Specification — prior art for structured API description; the REST equivalent of what MCP is becoming
Thank you.
메타데이터
- post_id
- e58c282f8ee0
- slug
- skill-first-api-development-e58c282f8ee0
- url
- https://medium.com/@yskprasad/skill-first-api-development-e58c282f8ee0
- canonical_url
- https://medium.com/@yskprasad/skill-first-api-development-e58c282f8ee0
- author_url
- https://medium.com/@yskprasad
- status
- ok
- fetched_at
- 2026-07-15 16:48:10