A CLI for Claude Code and Cursor to Call Third-Party APIs
Coding agents are good at running shell commands and bad at inventing API parameters. A CLI between the agent and the API fixes both: the agent names the operation, the command attaches the credential, checks the arguments, applies your rules and retries safely.
Key takeaways
- -Coding agents already run shell commands, so a CLI needs no integration work. The agent calls swy exec instead of curl with a bearer token.
- -Hiding the API key is only the first problem. The call still needs a schema check, an idempotency key, a policy and a log line.
- -There is no .env file. Credentials live in ~/.swytchcode/credentials.db and mode lives in .swytchcode/tooling.json.
- -Only methods you explicitly allow with swy add method can run, which is what stops an agent calling something you never approved.
- -A CLI cannot collect an end user's OAuth grant. If each customer connects their own Slack, you still need a hosted connect flow.
Yes, there is a command-line way to let Claude Code or Cursor call a real third-party API without pasting a token into the chat. The agent names the operation it wants. The command does the dangerous parts: it attaches the credential, checks the arguments against the real schema, applies your policy, sends the request, retries only what is safe to retry, and writes down what happened.
The command is swy, installed with npx swytchcode. MCP is the other door into the same runtime, and we will get to when each one is the right choice.

Why a CLI, of all things
It sounds like a step backwards. Everyone is building MCP servers, so why hand an agent a shell command?
Two reasons, and the first is boring but decisive: coding agents already run shell commands. Claude Code, Cursor, Codex, Windsurf and the rest all shell out as a matter of course. A CLI needs zero integration work, no server to keep running, no client config to debug. It works in CI, in a Dockerfile and in a Makefile, which an MCP server does not.
The second reason is that the failure mode of a coding agent is a plausible wrong call. Ask Cursor to refund a Stripe charge and you will often get a function that looks exactly right and uses a parameter that does not exist, or an endpoint that was removed two versions ago. We have written about this across a few tools: why Cursor writes outdated API calls, why Claude Code guesses API endpoints, and GitHub Copilot suggesting methods that do not exist. The pattern is always the same. The model is writing from memory of documentation, and its memory is a year old and slightly wrong.
A CLI in the path means the call is checked against the current schema before it leaves the machine, not after a 400 comes back.
The whole setup
Here is the entire thing. Note what is missing: there is no .env file anywhere in this.
npm install -g swytchcode # or just npx swytchcode
swy login
swy init --mode=sandbox --editor=cursorswy init creates a .swytchcode/ folder holding tooling.json with your version, mode and the list of integrations and allowed methods, plus an integrations/ folder with a manifest, a wrekenfile and a methods list per provider. The --mode flag is set once, here, and stored in that file. Your code never reads it and it is not an environment variable. Sandbox mode is the default worth starting in.
Next, pull in a provider and find the operation you want:
swy get stripe
swy discover "refund a charge"
swy info stripe.refund.create3swy discover searches by plain English description, which matters because the thing you must not do is guess a method ID. swy info prints the real inputs and outputs for that operation. Then you allow exactly one method:
swy add method stripe.refund.create3This is the step people skip and then miss. Only methods listed in tooling.json can run. If an agent asks for something you never added, the call fails at the runtime rather than reaching Stripe. That is the difference between an agent with a credential and an agent with a specific, enumerated permission.
Now the credential:
swy auth connect stripe
swy auth statusFor API-key providers this prompts you to paste the key. For OAuth providers like Gmail or Slack it opens a browser. Either way the secret lands in ~/.swytchcode/credentials.db, a local SQLite file outside your project folder, and your login session lives in ~/.swytchcode/auth.json. Nothing secret goes into the repo, into code, into a prompt or into an environment variable. The model never sees the key, which is the entire point of credential brokering.
Finally, run the call:
swy exec stripe.refund.create3 --param charge=ch_3QxYzAbCdEfGhIjKAnd check what happened:
swy audit network # what ran
swy audit policy # what got blocked
swy doctor # is this setup sane
What the CLI has to do beyond hiding the key
Keeping the token out of the chat is table stakes. If that is all your wrapper does, you have moved the problem rather than solved it. Four things actually matter.
A schema check. Coding agents invent parameters. This is not an occasional glitch, it is the standard behaviour of a model writing API code from memory. The runtime validates against the real method definition, so a hallucinated field fails locally with a clear error instead of producing a confusing 400 three steps later.
An idempotency key. Your agent framework will retry a timed-out call. Without a key on the retry, the second attempt is a brand new request and your customer gets two refunds. Swytchcode generates and reuses a key across the retries of a single execution when the integration declares execution_policy with mode: dynamic, so one exec means one effect. The mechanics are in idempotency explained.
A policy. An allow list stops unknown methods. It does not stop an allowed method being used badly. Policies are the layer where "refunds over $500 need a human" lives:
{
"id": "big-refunds",
"target": ["stripe.refund.create3"],
"when": { "field": "amount", "operator": ">", "value": 50000 },
"action": {
"type": "REQUIRES_APPROVAL",
"message": "Refunds over 500.00 need approval"
},
"approval_timeout": "2h"
}Keep that file in git and you can review changes to what your agent is allowed to do in a pull request. That is the argument in policy-as-code for AI agents, and the approval side is covered in human-in-the-loop approval.
A log line. Written by the process that sent the request, not by the model describing its intentions. If the agent writes its own log, blocked calls quietly vanish from the record. Logging every API call an agent makes goes through the fields.
CLI, MCP or SDK
All three are doors into the same runtime, with the same allow list, the same policies and the same audit trail. Pick by how the agent works, not by which is newer.
| Use it when | Why | |
|---|---|---|
| CLI | The agent already runs shell commands | No setup, works in CI and Dockerfiles, easy to read in a transcript |
| MCP | Cursor, Claude Code, Windsurf or Copilot should see operations as tools | The editor can list and call methods natively, with better argument prompting |
| SDK | You are writing the agent yourself | Typed calls, exceptions you can catch, multi-tenant support |
For MCP, the server runs with swy mcp serve and configuration for each editor is in the MCP server setup guide. If you are weighing a gateway against a runtime more broadly, MCP gateway vs execution layer is the longer answer.

The SDK version of the same Stripe call:
import { exec } from "@swytchcode/runtime";
try {
const res = await exec("stripe.refund.create3", {
body: { charge: "ch_3QxYzAbCdEfGhIjK" },
});
console.log(res.id, res.status);
} catch (err) {
// policy block, expired login, provider error, schema failure
console.error(err.message);
}Nothing about keys, retries or fetch. The runtime checks the method is allowed, runs the policies, injects the credential, retries rate-limit errors with backoff, parses the response and throws if the call failed. There are Python and Go versions of the same thing in runtime-py and runtime-go.
A real guardrail worth setting on a laptop
If a coding agent on a developer machine can reach your production Stripe account, you will eventually have an interesting Tuesday. Two specific rules are worth adding on day one.
Deny the destructive methods outright in your local project. Not "approve them," deny them. A developer who genuinely needs to issue a refund can do it in the Stripe dashboard with their own login, which also means it shows up under their name rather than under the agent's.
Keep --mode=sandbox on any project an agent touches until you have watched swy audit network for a week. The audit output tells you what your agent actually tried to do, which is reliably different from what you assumed it would do.
When a CLI is the wrong tool
The CLI runs on one machine with one set of credentials. That is exactly right for a coding agent on a laptop, a CI job or a background worker. It is wrong for a multi-tenant product.
If each of your end users must connect their own Gmail or Slack, you need a hosted connect screen, a grant stored per customer, and every call tagged with that customer ID. A CLI does not collect that grant and should not try to. Use Nango, Composio, Arcade or Pipedream Connect for the screen. That split is covered properly in multi-tenant OAuth for AI agents and the wider landscape is in best tools for AI agents to call APIs.
The CLI is also the wrong shape if your agent runs inside a hosted platform with no shell. Use the SDK or MCP there.
What this costs
The first two live commands do not need an account. The free plan is $0 forever and covers 100 live commands a month, 10 connected end users and 7-day log retention, with allow and deny rules included. Pro is $29 a month or $290 a year for 10,000 live commands and 30-day retention. Business is $149 a month or $1,490 a year for 1,000,000 live commands, 90-day retention, five seats and approval workflows. For a single developer pointing a coding agent at a sandbox, the free plan is the whole story.
One more thing that matters more than it sounds: every API added to Swytchcode becomes agent-ready in minutes, and its specs and documentation are then watched for breaking changes. The reason your agent wrote a deprecated call in the first place was stale knowledge. A runtime that notices when the vendor moves is how you stop that happening again rather than just catching it once.
FAQ
Is there a command-line tool that lets Claude Code or Cursor call third-party APIs safely?
Yes. Have the agent run swy exec <method> instead of calling the vendor API with a token from the environment. The command validates the arguments against the real schema, checks the method is on your allow list, applies your policies, injects the credential from a store outside your repo, retries safely and logs the result. Use the MCP server instead when you want the editor to see the operations as native tools.
Why not just give the agent a curl command and an API key?
Because the key then lives somewhere the model can read, and the call has no schema check, no idempotency key, no policy and no log. The first curl works. The problem is the retry that sends a second email, the hallucinated parameter that returns a confusing 400, and the refund nobody can trace three weeks later.
Where does the API key actually go?
Into ~/.swytchcode/credentials.db, a local SQLite file in your home directory, outside the project. Your login session is in ~/.swytchcode/auth.json. Nothing secret goes in the repo, in code, in a prompt or in an environment variable, and the model never sees it.
Do I need to set SWYTCHCODE_MODE or any environment variables?
No. Mode is set once with swy init --mode=sandbox or --mode=production and stored in .swytchcode/tooling.json. There is no environment variable for it and your code never reads it. If you see a Swytchcode example using .env, it is wrong.
Can the agent call an operation I did not approve?
No. Only methods you have added with swy add method <canonical_id> are listed in tooling.json, and anything else fails at the runtime before a request goes out. swy audit policy shows you what got blocked.
How do I find the right method ID?
Run swy discover "<what you want to do>" to search by description, then swy info <canonical_id> to see the real inputs and outputs, or swy list methods <provider> for the full list. Do not let an agent guess an ID. Guessed IDs are the whole problem this is meant to solve.
Does this work in CI?
Yes, and it is one of the better reasons to prefer the CLI over MCP. The same swy exec call works in a GitHub Action or a Dockerfile, with credentials connected once on the runner. Working projects are in swytchcode-examples, and the full command reference is in the CLI docs.
More content
How to Log Every API Call an AI Agent Makes
Log the call where it is sent, not where it is described. Record the operation, the actor, the idempotency key, the policy decision and the outcome. Never record the credential. If the agent writes its own log, the calls that were blocked quietly disappear.
Composio Pricing Compared with Nango, Arcade, Pipedream, and Swytchcode
Composio is free for 100,000 tool calls a month, then $29. Nango is $50 pay-as-you-go. Arcade Team is $25 plus a cent a call. Pipedream Startup is $99 billed annually. Swytchcode is $149 for a million. The headline prices are the least useful part, so here is the arithmetic.
Multi-Tenant OAuth for AI Agents: How to Store a Credential for Every Customer
Multi-tenant OAuth means one stored grant per customer, not one token in a .env file. If every customer connects their own Slack or GitHub, you need a hosted connect flow, a credential stored against their ID, and every call tagged with whose account it used. Here is who does what.
