DEV Community

Valentin Lemort
Valentin Lemort

Posted on

AI agents suck at using APIs. We tried. Here's what we built to fix it.

AI agents suck at using APIs. We tried. Here's what we built to fix it.

We’ve been been building API automation software since 2019 — lots of internal glue code, tools for clients, and APIs on top of APIs.

When LLM agents started getting good, we tried wiring them into our stack.

It didn’t go well.

Why?

Agents don't understand relationships between objects
They fail to understand the specificities of each API if it goes against their training data
They are not even that great at generating valid JSON
They don’t retry on failure.

They need structure. Clear inputs and outputs. Contracts they can reason about.

We looked at Model Context Protocol (MCP) — a spec for exposing actions and resources in a machine-friendly way.

It makes sense. But writing an MCP server by hand is painful.

Too much boilerplate. Too many edge cases. Not fun.


So we built mcpresso

It’s a small TypeScript framework to define MCP-compatible servers with:

  • schema validation via Zod
  • metadata exposure by default. So the agent knows exactly what it is dealing with
  • JSON-RPC routing
  • retries, rate limiting, etc.

Minimal setup. Just define your resources and actions.

It outputs for the agent:

  • The resources
  • The tools
  • The metadata to understand:
    • The structure of the API
    • The relationships between objects.

Here’s what it looks like:

import { createResource } from "mcpresso"
import { z } from "zod"

export const invoice = createResource({
  id: "invoice",
  actions: {
    get: {
      input: z.object({ id: z.string() }),
      output: z.object({
        amount: z.number(),
        status: z.enum(["paid", "unpaid", "canceled"]),
      }),
      handler: async ({ input }) => {
        const invoice = await fetchFromDB(input.id)
        return {
          amount: invoice.amount,
          status: invoice.status,
        }
      },
    },
  },
})
Enter fullscreen mode Exit fullscreen mode

Then expose it:

import { createMcpressoServer } from "mcpresso"

export const server = createMcpressoServer({
  resources: [invoice],
})
Enter fullscreen mode Exit fullscreen mode

That’s it. You can run this locally, or throw it on Vercel/Cloudflare.

📘 Repo

🌐 LP


Try it

npm install mcpresso zod
Enter fullscreen mode Exit fullscreen mode

Build your server. You're done.


What’s next

We’re using mcpresso as the base for:

  • a generator that converts OpenAPI specs into MCP servers
  • an agent that reads docs and generates MCP logic
  • a secure runtime with RBAC + human-in-the-loop

But right now, we just wanted to make this part not suck.


Got feedback?

This stuff is early. The spec might evolve.

We’re building in the open — and learning as we go.

If you’ve run into similar issues building for agents, let us know.

🗣 GitHub Discussions

Top comments (0)