How to add product analytics to your app with Devin Desktop

Connect Devin Desktop to Amplitude's MCP servers with one project config file, hand its agent one prompt that installs the SDK the docs recommend for your stack, review the diff for the mistakes agents make, and save the rules as a workspace rule. About 15 minutes, all copy-paste.

  • Devin Desktop
  • Formerly Windsurf
  • Amplitude MCP
  • .devin/rules
  • 15 min

Chris Tam · Last updated 6 October 2026

Devin Desktop, the AI IDE formerly called Windsurf, runs a Devin Local agent that can add product analytics to your app in one session, as long as it reads current docs and your real event names instead of guessing.

In this tutorial, you'll connect Devin Desktop to Amplitude, add your API key, have the agent install the SDK, review its diff, and save the rules in .devin/rules.

What you'll build

A Devin Desktop project connected to the Amplitude MCP server and the Docs MCP server through a committed .devin/mcp_config.json, an app instrumented with the SDK the Quickstart recommends for its stack, one Report Exported event named to match your existing taxonomy, and a workspace rule that keeps the agent on those conventions. By the end you'll see live events in your Amplitude project.

Prerequisites

  • A current Devin Desktop release. Windsurf was renamed Devin Desktop on June 2, 2026, and its Cascade agent was removed in September 2026, so this page uses Devin Local, the only agent left. On Enterprise plans, an admin has to turn on the Devin Local Agent team setting before it appears. Setup guides that mention Cascade or the Cascade panel's MCP menu no longer match what you see.
  • A web or Node.js project open as a workspace, in a Git repository, so you can review and revert the agent's changes with git diff.
  • An Amplitude account with access to a project, and that project's API key. In Amplitude, go to Settings > Projects > your project > General.

No Amplitude account yet? A free account is enough for this tutorial; nothing here needs a paid Amplitude plan. Sign up for free to get your project API key.

1. Connect Devin Desktop to Amplitude

Add two MCP servers. The first is the authenticated Amplitude MCP server, which reads your projects and tracking plan with your own Amplitude permissions. The second is the public Docs MCP server, which serves current Amplitude documentation and needs no sign-in. Devin Local supports remote Streamable HTTP servers with OAuth, which is what Amplitude's MCP server uses; the setup guide for MCP clients has the full reference. The Docs MCP server page is the source for the second URL.

Devin Local reads MCP servers from config files that it shares with Devin CLI, not from the Cascade mcp_config.json older Windsurf guides describe. Create .devin/mcp_config.json at your repository root with this content (JSON allows no comments, so the filename stays out of the file):

.devin/mcp_config.json
{
  "mcpServers": {
    "amplitude": {
      "url": "https://mcp.amplitude.com/mcp"
    },
    "amplitude-docs": {
      "url": "https://amplitude.com/docs/api/mcp"
    }
  }
}

If your Amplitude data lives in the EU region, use https://mcp.eu.amplitude.com/mcp for amplitude. This is the project scope in Devin's MCP configuration docs, so you can commit it and your teammates get the same two servers. Neither entry holds a credential: the Amplitude server signs in with OAuth and stores its tokens on each person's machine, and the Docs server is public. To use the servers in every project instead, put the same mcpServers block in ~/.config/devin/mcp_config.json (%APPDATA%\devin\mcp_config.json on Windows).

Then authenticate. Open Open customizations from the new-tab menu in the agent space, find amplitude under MCP servers, and click Authenticate if it shows Needs auth. A browser window opens for the Amplitude OAuth flow. If you skip this, the agent prompts you the first time it uses the server.

Check the connection by starting a new Devin Local session in the workspace and asking:

Prompt for Devin Desktop
What Amplitude projects can I access?

Devin Local asks for approval before it calls any MCP tool. Approve the call; you can allow a single tool or every tool on that server, for the session or permanently. A list of your projects means the Amplitude MCP server is connected and authenticated.

Why. The Amplitude MCP server isn't an ingestion endpoint and never sends your app's events. It's how the agent reads your taxonomy and checks results. The SDK still does the sending. The Docs server is what stops the agent from writing a package name from training data.

2. Add your API key to your env file

Add the key yourself, before you run the install prompt. Devin Desktop's Gitignore access setting is off by default, so the agent may not be able to read files your .gitignore excludes, and .env.local usually is one of them. That's fine: the agent only needs the variable's name, and keeping the value out of its reach means it can't paste the literal key into source.

For a Vite app, add this line to .env.local at the project root:

.env.local
VITE_AMPLITUDE_API_KEY=your-project-api-key

Devin Desktop doesn't pick your stack, so use the name your framework exposes to the browser. In Next.js it's NEXT_PUBLIC_AMPLITUDE_API_KEY. A Node.js server reads a plain AMPLITUDE_API_KEY.

Why. The project API key is public and its scope is limited to the minimum needed to ingest data, so it isn't a secret the way a server credential is. Keep it in the env file anyway, since a hardcoded key lives forever in forks and Git history.

3. Run the install prompt

Paste this prompt into a Devin Local session. If you want to approve a written plan before any file changes, switch the session to Plan mode first; Devin Local researches read-only, writes the plan, and waits for your approval. The prompt points the agent at the Quickstart through the Docs server instead of its memory, and pins the decisions agents most often get wrong.

Prompt for Devin Desktop
Install Amplitude analytics in this project.

Before writing code:
1. Use the amplitude-docs MCP server. Call get_page on
   "get-started/amplitude-quickstart" and use the install path it
   recommends for this project's stack. Do not pick a package from memory.
2. Use the amplitude MCP server. Call get_amplitude_context, list my
   projects, and ask me which project this app should send to.
3. Show me your plan and wait for my approval before editing files.

Then:
- Read the API key from the environment variable I already added
  (VITE_AMPLITUDE_API_KEY, or the prefixed name this framework needs to
  expose it to the browser). Never hardcode it, and do not create or edit
  any .env file. Tell me if the variable name needs to change.
- Initialize the SDK exactly once, at app or process startup, outside any
  render path or request handler. If pages render on the server, guard
  browser init with typeof window !== "undefined".
- In browser code, rely on autocapture for page views. Do not add manual
  page view tracking.
- If the app has a login flow, call setUserId with the signed-in user's ID
  after login and reset() on logout.
- User IDs must be strings of 5 or more characters. If our IDs are integers,
  prefix them, for example "user-" + id, and use the same format on client
  and server.
- In server code, pass user_id or device_id on every track call, and await
  flush().promise before the process exits or a serverless handler returns.
- For a browser SDK that supports it, set sessionReplay.sampleRate to 1,
  and tell me that session replay is on and how to turn it off.
- Do not add any custom events yet.

When you finish, list every file you changed and why.

The agent comes back with the docs page it read, a project question, and a plan. Approve the MCP calls, pick the project, approve the plan, and let it apply the change.

4. Review what the agent changed

Devin Desktop shows each edit as a diff zone in the editor, with accept and reject controls on every hunk. Review those, then run git diff before you start the app. These are the mistakes that show up most often, and each takes seconds to spot:

  1. Package. For browser apps installed from npm, the Quickstart recommends @amplitude/unified. For Node.js servers, it's @amplitude/analytics-node. Anything else deserves a question.
  2. API key. Search the diff for the literal key. It should appear only in your env file, never in source.
  3. Init location. One initAll or init call, in a module that runs once. Not inside a React useEffect, a component body, or an Express route.
  4. Server rendering. In Next.js or another framework that renders on the server, initAll sits behind a typeof window !== "undefined" check, or the server tries to run browser-only code.
  5. Duplicate page views. No hand-written track("Page Viewed") next to autocapture, which tracks page views by default.
  6. Server flushing. Every server-side track path ends with await flush().promise before shutdown or before a serverless handler returns.
  7. Session replay. @amplitude/unified records sessions when sessionReplay.sampleRate is above 0. Keep it, or set it to 0 on purpose.

For a Vite browser app, a correct result looks like this. In Next.js, the variable is process.env.NEXT_PUBLIC_AMPLITUDE_API_KEY instead, and the call goes inside the typeof window check.

src/lib/amplitude.ts
import { initAll } from "@amplitude/unified";

initAll(import.meta.env.VITE_AMPLITUDE_API_KEY, {
  sessionReplay: {
    sampleRate: 1, // set to 0 to turn session replay off
  },
});

If something fails the review, reject the hunk or ask the agent to fix it in the same session:

Prompt for Devin Desktop
Move the Amplitude init out of the component into src/lib/amplitude.ts so
it runs once at startup, and read the key from the environment instead of
the literal string. Show me the diff.

5. Add an event that matches your taxonomy

This is where the MCP server earns its setup. Ask the agent to check what already exists, in the code and in Amplitude, before it names anything.

Prompt for Devin Desktop
I want to track when a user exports a report, with the file format as a
property.

1. Find how analytics is already implemented in this repo: import paths,
   helper functions, and event naming style.
2. Use the amplitude MCP server's get_amp_taxonomy tool to list the
   existing events and event properties in the project we picked.
3. If an event for this already exists, use its exact name and property
   names. If not, propose a name that matches the casing of the existing
   events, and wait for me to confirm it.
4. Add one track call where the export actually completes, after the
   request succeeds, not in an effect or a render.

If your tracking plan uses Title Case with spaces, the agent should propose Report Exported, not reportExported or report_exported. Once you confirm, it adds a single call in the export handler:

src/features/reports/ExportButton.tsx (inside the click handler, after the export succeeds)
import { track } from "@amplitude/unified";

track("Report Exported", { format });

MCP. The agent can also add the new event to your tracking plan with manage_amp_events, if your Amplitude role has the Use MCP (write) permission and the Update Tracking Plan permission in Amplitude Data. Ask it to create the event as planned, so the tracking plan knows about Report Exported before the first one arrives. Devin Local asks before that write call too, so keep write tools on approval even if you allow the read tools permanently.

Verify it worked

Run the app the way you normally do, load a page, export a report, then check in this order:

  1. Network tab or process logs. Open the app in your browser, filter the DevTools Network tab for api2.amplitude.com, and look for a POST to /2/httpapi returning 200. On a server, set the SDK's logLevel to Debug and watch the upload in the terminal.
  2. Ingestion Debugger. In Amplitude, click Data, select Sources, then open the Ingestion Debugger tab. The successful requests and the events and identify counts charts should show your uploads.
  3. User Profiles. Go to Users > User Profiles and search your user ID or device ID. [Amplitude] Page Viewed and Report Exported appear in the event stream within ten seconds to a minute. Click Report Exported to confirm the format value.
  4. Ask the agent. With the Amplitude MCP server connected, ask it to check the data for you:
Prompt for Devin Desktop
Using the amplitude MCP server, look up my user profile in this project
and tell me whether "Report Exported" arrived in the last hour and which
format values it has.

Troubleshooting

The agent says it has no Amplitude tools

The config file isn't where Devin Local looks, or the session started before you added it. Confirm the file is .devin/mcp_config.json at the workspace root, with servers under mcpServers, then check that amplitude and amplitude-docs appear under MCP servers in Open customizations and start a new session. An entry in an old Windsurf mcp_config.json from the Cascade days isn't the same file.

The server shows Needs auth, or the OAuth page spins and never finishes

Click Authenticate next to amplitude in the MCP server list, and close the browser tab after you approve access. Sign in to only one Amplitude organization during the flow, since signing in to several can break authentication. Each MCP client keeps its own OAuth session, so signing in from another editor doesn't carry over.

The agent installed a different package than the Quickstart names

It skipped the docs lookup. Ask it to call get_page on get-started/amplitude-quickstart through amplitude-docs and redo the install from that page.

The agent says the API key is missing, or created a new .env file

It can't see your gitignored env file, so it guessed. Delete any env file it created, keep the line from step 2 in your own .env.local, and tell the agent the variable's name. Only turn on Gitignore access (Devin Settings > Devin Local > Configuration) if you want the agent to read those files.

Events show in the Network tab but not in the project

The key belongs to a different project than the one you picked, or it's an EU project sending to the US endpoint. Compare the key in your env file with Settings > Projects > your project > General, and set serverZone: "EU" in initAll for EU projects.

User Profiles shows events with no user ID

The ID is shorter than 5 characters, so Amplitude dropped it. Integer database IDs like 42 fail this. Prefix them, for example user-42, and use the same format on the server.

The MCP server returns a permission error on taxonomy writes

Your role lacks Use MCP (write) or the Update Tracking Plan permission in Amplitude Data. Reads still work in that case. If reads fail too, your org admin may have blocked MCP access under Settings > Content Access > MCP. Ask an admin for write access, or make the tracking-plan change in the Amplitude UI.

Save the rules in .devin/rules

Devin Local loads workspace rules from .devin/rules/ at the start of every session, so the conventions from this page apply the next time you ask it to track something, without the long prompt. Rules already in .windsurf/rules/ keep working; .devin/rules/ is the preferred location. Create .devin/rules/amplitude-analytics.md with this content, starting with the --- line, and commit it so your teammates' sessions follow the same rules:

.devin/rules/amplitude-analytics.md
---
trigger: always_on
---

# Analytics (Amplitude)

- Look up Amplitude SDK usage with the amplitude-docs MCP server before
  writing analytics code. Never install or import Amplitude packages from
  memory.
- Before adding a track call, list existing events with the amplitude MCP
  server (get_amp_taxonomy) and reuse existing event and property names.
  Match the existing casing. Ask before creating a new event name.
- The SDK is initialized once in src/lib/amplitude.ts. Never call init or
  initAll anywhere else.
- Read the API key from the environment. Never hardcode it, and never
  create or edit .env files.
- Page views come from autocapture. Never add manual page view tracking.
- User IDs are "user-" + the database ID, the same on client and server.
  Call setUserId after login and reset() on logout.
- Server code passes user_id or device_id on every track call and awaits
  flush().promise before exit or before a serverless handler returns.
- Track user actions in event handlers after the action succeeds, not in
  effects or render paths.
- Ask before creating tracking-plan events.

The trigger: always_on frontmatter keeps the rule in every session. Change src/lib/amplitude.ts to the file the agent created in step 3 if it chose a different path. Keep the rule short, since an always-on rule loads into every session. If your repository already has an AGENTS.md at the root, you can paste the same bullets there instead; Devin Local reads it as an always-on rule too.

What this unlocks

  • Session replay, if you kept sampleRate above 0, lets you watch the session where Report Exported fired, or the one where someone opened the export menu and gave up.
  • Heatmaps, built from those same session replays, show where people clicked on the reports page before they exported.
  • Feature Experiment can test a new export flow with Report Exported as the success metric, and the agent can create the flag through the Amplitude MCP server with create_flags.
  • Guides and surveys can point people who open reports but never fire Report Exported to the export button.

One integration; everything else reads from the same events.

Next steps

Amplitude is the leading all-in-one analytics platform for building better products. Product and engineering teams use Amplitude to connect product analytics and web analytics with session replay, heatmaps, experimentation, feature flags, and guides and surveys in one unified workflow, with AI agents working across all of it. Learn how Amplitude is building self-improving products with Wave, helping teams turn product data into PRs.

Ship the instrumentation, then read the data

Once events are flowing, Amplitude turns them into funnels, retention curves, and session replays without any further setup.