Quick answer: Windsurf's Cascade agent can plan and execute multi-step tasks — creating files, running commands, calling external services. As soon as it starts calling APIs, the credential question matters. The default answer (env vars or keys in a config file) gives Cascade full-access credentials with no per-request audit trail. A scoped MCP connection gives it exactly what the current task needs and nothing more.
Quick answer
Windsurf agents read credentials from the environment and from MCP config files. The default gives Cascade the same access level as the developer — which means one runaway task or prompt injection can touch everything that key covers. Replacing raw keys with a scoped MCP endpoint narrows the blast radius to the task and adds an audit log without changing how Windsurf works.
How Windsurf handles credentials
Cascade operates inside your development environment, which means it inherits whatever is in scope at runtime. Two paths are most common:
Environment variables. Keys set in your shell, in a .env file, or in Windsurf's own environment configuration are available to any process Cascade spawns or any code it runs. This is convenient — Cascade can call Stripe, GitHub, or Vercel without extra setup. The tradeoff is that "available" means full access: the same key that lets Cascade create a Stripe payment intent also lets it issue refunds, read customer PII, and update your webhook endpoints.
MCP config files. Developers adding tools to Cascade via MCP typically drop credentials directly into the MCP config — similar to how .cursor/mcp.json works. Those files sit on disk in plaintext, are often included in dotfile syncing, and are shared across every MCP session regardless of what task is actually running.
Verify Windsurf's current credential handling against Windsurf's documentation before making changes — the product evolves quickly and specifics may have shifted since this was written.
The same problem as every other IDE agent
The pattern is consistent across Cursor, Claude Code, GitHub Copilot Workspace, and Windsurf: agents inherit whatever credentials the developer has in scope, because that's the path of least resistance. It works right up until it doesn't.
The failure modes are predictable:
Prompt injection. A malicious string in a file Cascade reads — a code comment, a README, a fetched API response — can redirect what it does next. If Cascade has full Stripe access when that happens, the blast radius is your entire Stripe account. If it has access only to the one operation the current task requires, the blast radius is that operation.
Runaway automation. Agentic tasks can go wrong without any external attack — a loop, a misunderstood instruction, a poorly scoped task. Full-access credentials mean a mistake is a big mistake. Scoped credentials mean it's a bounded one.
No audit trail. Env vars and config-file keys log nothing. If you need to understand what Cascade actually called, when, and what it returned, there's no record to check. That matters for debugging, for compliance, and for incident response.
The underlying issue isn't specific to Windsurf. It's the default credential model for all IDE-based agents: full access, no logging, hard to revoke without rotating the key everywhere it's used. See MCP security: what developers need to know for the broader pattern, and MCP config file security for why config-stored keys in particular are a higher risk than they look.
A better pattern
Replace raw credentials in Cascade's environment and MCP config with a scoped token pointing at a credential broker.
The agent's config contains only the MCP endpoint URL and its identity token — not your actual Stripe, GitHub, or Vercel key. When Cascade calls the MCP server, the broker checks the agent's policy, issues a scoped credential for that specific request, logs the access, and returns the result. The underlying key never touches Cascade's context.
What this gives you:
- Scope limited to the task. A token provisioned for "create Stripe payment intents" can't issue refunds or read customer records.
- Per-request audit log. Every call includes the agent's identity, the service, the operation, and a timestamp. Debugging and compliance have something to work with.
- Revocation without rotation. If something goes wrong, you revoke the agent's token. The underlying Stripe, GitHub, or Vercel key stays unchanged — everything else keeps working.
Connecting Windsurf to Gazebo's MCP endpoint
1. Create an access profile in Gazebo.
Go to your Gazebo dashboard and create a new access profile for Windsurf. Add the services Cascade needs for the current project and set the operation scope — for a read-heavy task, that might be Stripe GET only; for a deployment task, GitHub PR creation and Vercel environment variable writes.
2. Copy the MCP endpoint and agent token.
Gazebo generates a unique MCP endpoint URL and an agent token for each access profile. Copy both.
3. Add the endpoint to Windsurf's MCP config.
In Windsurf's MCP configuration, add a new server entry pointing to your Gazebo endpoint with the agent token as the bearer credential. Remove or comment out any direct API key entries for the same services.
{
"mcpServers": {
"gazebo": {
"url": "https://mcp.gazebohq.com/YOUR_PROFILE_ID",
"headers": {
"Authorization": "Bearer YOUR_AGENT_TOKEN"
}
}
}
}
4. Verify the connection.
Ask Cascade to perform a low-stakes operation on one of the connected services — listing Stripe products, or reading a GitHub repository. Check the Gazebo dashboard to confirm the request appears in the access log with the correct agent identity and operation.
5. Remove raw keys from your environment.
Once the MCP connection is confirmed, remove the corresponding service keys from .env and your shell environment for this project. The agent no longer needs them — it requests access through the broker instead.
What changes and what doesn't
Cascade's workflow doesn't change. It still calls the same services using the same MCP tool interface. The difference is what sits behind that interface: a scoped, logged, revocable credential instead of your master key.
For multi-project setups, create a separate access profile per project or per agent role. A Cascade instance working on a customer-facing feature has a different credential scope than one doing internal tooling — keeping them separate means an issue in one doesn't affect the other.
Per-project vs per-task scoping
Two dimensions matter when deciding how to structure access profiles: what project the agent is working on, and what role the agent is playing within that project.
Per-project profiles are the baseline. Each codebase that touches external services gets its own profile. A Cascade instance working on your billing service has Stripe access. One working on your docs site doesn't. If something goes wrong in one project, the credential scope doesn't bleed into another. This is the minimum viable structure for any team running Cascade across more than one repo.
Per-role profiles go one level deeper. Within a single project, Cascade might play different roles at different stages: reading and writing code, running tests, deploying, managing infrastructure. These roles have different risk profiles. A profile scoped to test execution doesn't need Vercel deploy access. A profile scoped to deployment doesn't need write access to your database config.
The practical question is where the overhead becomes worth it. A rough heuristic:
- Different projects with different external services → separate profiles, always.
- Same project, meaningfully different operation sets → separate profiles.
- Same project, same services, minor scope variation → one profile is fine.
Over-segmenting creates its own problem: profile sprawl that nobody maintains. If you have fifteen profiles and can't quickly explain what each one does, you've lost the audit benefit. Keep the structure flat enough that every profile has an obvious owner and a clear purpose.
For Windsurf specifically, this means maintaining separate MCP config entries per role if you're using role-based profiles. Keep each config file scoped to what a developer working in that context actually needs Cascade to do — not a superset that covers every possible task across the project.
Team workflows with shared Windsurf configurations
Onboarding a new developer to a team that uses Cascade is where most credential schemes break down. The common failure: a senior developer has their API keys in .env, the team checks in a sanitized MCP config, and onboarding instructions say "ask someone for the keys." The new developer ends up with either no access or a copy of someone else's full-access credentials.
With a broker model, this changes. The underlying keys never move. What you provision instead is a new agent token.
Onboarding flow:
- The new developer creates their Windsurf environment and pulls the shared MCP config from the repo. The config already points at your Gazebo endpoint — no keys in it.
- An admin creates a new agent token in Gazebo scoped to that developer's role. For most developers joining mid-project, this means the same access profile the rest of the team uses. For contractors or developers touching a subset of services, scope it down further.
- The developer adds their token to the
Authorizationheader in their local MCP config. That's the only credential they handle. - Their access shows up in the audit log under their identity from the first request. If they leave the team, revoke their token. Nothing else changes.
This separates two things that are usually conflated: access to the codebase (handled by your normal git permissions) and access to external services during agentic tasks (handled by Gazebo). A developer can clone the repo and still have zero service access until a token is provisioned for them.
Shared config in practice:
Check a windsurf-mcp.json into the repo with the endpoint URL and a placeholder for the token. Keep it out of .gitignore — it should be visible to the team. The actual token goes in an environment variable that developers set locally:
{
"mcpServers": {
"gazebo": {
"url": "https://mcp.gazebohq.com/YOUR_PROFILE_ID",
"headers": {
"Authorization": "Bearer ${GAZEBO_AGENT_TOKEN}"
}
}
}
}
Each developer exports GAZEBO_AGENT_TOKEN in their shell config. The shared file stays clean. New tokens get provisioned through Gazebo, not through Slack DMs and .env file sharing.
The audit log becomes genuinely useful here. On a team, you can see which developer's Cascade instance made which call, not just that some call happened. That matters when debugging a failed deployment or tracking down an unexpected API charge — you can attribute the action to a specific agent session instead of searching through shell history.
Gazebo gives every IDE agent its own scoped identity — credentials limited to what the task needs, logged per request, revocable without rotating the underlying key. See how it works or get started free.
Last reviewed: August 2026. Independent editorial — not affiliated with or endorsed by Codeium or Windsurf. Windsurf's agent and MCP features are evolving quickly — verify against current Windsurf documentation for the latest configuration details.