← Back to Blog

2026-08-297 min read

Vibe Coding and the Function That Does Not Exist

Generated code can read perfectly and still call a method your library does not have. Here is how to give a coding tool the context it needs, and a verification loop sized to what the change can cost.

You describe the feature, the tool drafts it, and the code reads like something you would have written yourself. Sensible names, the right file, the pattern the rest of the project uses. Then you run it:

TypeError: config.onReady is not a function

onReady is a perfectly reasonable name for that callback. The installed package calls it onLoad. Nothing in the draft looks careless, because nothing in it is careless. It is internally consistent, and it calls a function the library does not have.

That moment is the one worth designing around. Vibe coding, meaning you describe what you want, let a tool draft it, run it and refine, is genuinely good at exploration and at the repetitive parts of a build. What decides whether the drafts hold up is whether the details the tool needed were in front of it, and whether checking the ones that matter is cheap enough that you do it.

Where a plausible detail comes from

A coding tool works from what it has learned and from what is in the session. That usually means your prompt, the files you have open, nearby implementations, your repository instructions, and the errors that came back last time. When the detail a task depends on is in there, the draft fits your project closely.

The details most likely to be missing are the ones outside your repository. Your code shows local patterns very well. It does not carry the current reference for a package you installed last month. Releases moving underneath you is the ordinary case: a method arrives in a newer version, an import path moves, an option is replaced. onReady against onLoad is that gap in a single line.

Give the tool the smallest context that covers the task

Choose sources for the task, not for coverage. For an authentication change that is the current authentication guide, the installed version of the package, the middleware and session code you already have, a maintained sample for your framework, and any security requirements your project holds. That set is enough to write the change correctly.

More sources are not more context. Attaching everything makes it harder to tell which version or which pattern applies, so the tool has to pick between several answers that are all correct somewhere. State the task, the constraints and the expected behaviour instead, and let the sources cover the task.

Ask for the evidence inside the prompt

A prompt can request the check along with the change:

Add GitHub sign-in using the authentication package already installed in this
repository. Follow the existing session pattern. Before editing, identify the
installed version and cite the relevant provider configuration from the
connected documentation. Run the auth tests after the change.

Four useful things happen there. The tool inspects local state, uses a source for the external details, follows a pattern you already decided on, and finishes by verifying its work against something other than its own explanation.

Match the depth of checking to the cost of failure

A prototype and a payment path do not deserve the same scrutiny. A layout change is verified by opening the page and clicking it. Authentication, billing, authorisation, data deletion and migrations earn targeted tests and a careful read, because being wrong there costs more than a second attempt.

The loop, in order:

  1. Request a small change. A narrow diff is easier to read and easier to undo.
  2. Ask for the evidence. Which file, type or documented section supports the unfamiliar part of the change.
  3. Read the diff. Scope, assumptions, error handling, and anything that changed which you did not ask about.
  4. Run the static checks. Compiler, linter, type checker.
  5. Run targeted tests. The behaviour you changed, and the failure paths that matter.
  6. Check external details against their source. New methods, new options, changed import paths.
  7. Run the application. Integration problems show up in behaviour first.

Evidence beats a second opinion. Asking the same tool whether it is sure produces another explanation, and an explanation is not a check. Types, tests, retrieved passages and what the program actually does are checks.

The habit worth having: ask what the source is

When a draft uses a method you do not recognise, ask where it is documented before you ask whether it works.

Most of the time you get a real answer and it takes seconds to confirm. Open the passage and check that it describes the same package, the same version and the same runtime you are on. Read a little above and below it, because the condition that makes the example work is often a paragraph earlier: a prerequisite, an initialisation step, a note that the option is experimental.

When there is no source, that is information rather than a dead end. It tells you the detail came from pattern rather than from a reference, which is exactly the case that deserves two more minutes. Search the installed types or the package source. If the method is there, keep it and move on. If it is not, you have found your onReady before it cost you a debugging session.

Asking early is the cheap version of asking later. The question gets answered either way: now, by reading one paragraph, or in half an hour with a stack trace in front of you.

Put the sources behind one endpoint

Model Context Protocol lets AI clients discover and call external tools, so the reference material can sit in the session instead of a browser tab. A documentation server can offer search, passage retrieval, API reference lookup and code example retrieval.

Retrieved passages are evidence you can open. Each one comes back with the address it came from, which is what makes step two of the loop quick rather than aspirational. Keep your type checks, your tests and your code review; a connected source makes checking a detail cheap, and cheap checking is what turns a loop into a habit.

One endpoint can cover the sources a single task spans. Framework documentation with its sample repository. An API reference with a working integration. Deployment documentation with the operations runbook. A component library guide with your own design system notes.

MCP Studio can create that endpoint from documentation sites, GitHub repositories, websites, PDFs and existing MCP sources, without writing server code.

MCP Studio source setup wizard

After deployment, configure the endpoint in your MCP client:

{
  "mcpServers": {
    "my-app-docs": {
      "url": "https://appatools.com/mcp-studio/api/mcp/my-app-docs-q7t4n1"
    }
  }
}

Follow the client connection guide, wait for indexing, then try it with questions tied to what you are building: which authentication method the guide recommends, the documented props for a component, the example that handles a particular callback, whether a deployment option applies to the version you have installed. An existing MCP endpoint added as a source contributes retrieval context; remote action tools are not exposed through the generated server.

The standard you hold

Context settles the technical details. You settle everything else. Whether the implementation matches the requirement, whether the security and privacy boundaries are right, whether the failure handling is sufficient, whether the result is maintainable and whether the experience is good enough to ship are yours to decide, and they always were.

Generated code goes through the same gates as code you typed. Producing a draft is cheap. The bar for shipping one is not, and holding it there is what makes the speed worth having.

A draft that names a function which does not exist is not an argument for writing less with AI. It is an argument for keeping the reference close and spending your checking where a mistake would cost you something. Do that and the fast path stays fast.

Create a context server with MCP Studio to give your coding client the sources your next task depends on.

Keep learning