Don't type personal details, such as a client's name.

Connecting an AI Agent (MCP)

Connect Claude, ChatGPT, Cursor or your own agent to your business workspace through MCP, so it can prepare DS-160 forms from a client's documents and send client links.

An immigration firm’s own AI agent can work in its DS160.io workspace through MCP (the Model Context Protocol). From a client’s documents or emails, the agent can create a form, fill in the answers it finds, check what is still missing, and send the client a link to complete the rest. Your staff then check the application and sign it on CEAC themselves.

The agent connects to one business workspace and can do only what you allow it to. Each thing it can do is also an endpoint of the DS160.io API.

Before you start

  • A business workspace. MCP is available on business workspaces.
  • Owner or Admin access. Only a workspace’s Owners and Admins can create API keys or allow a connection.
  • An MCP client. Claude Code, Cursor, VS Code, Codex and Windsurf connect with an API key. claude.ai and ChatGPT connect by signing in to DS160.io.

The server’s address is:

https://www.ds160.io/api/mcp

Use this address even if your workspace has its own domain.

Connect with an API key

  1. Open Workspace Settings → Team & access → API Keys and click Create API Key.
  2. Name the key after the agent (for example Claude Code, intake team), choose the MCP preset, and create the key. The preset ticks every scope except runs:write; untick any scope the agent does not need.
  3. Copy the secret. It starts with ds160_sk_ and is shown only once.
  4. Add the server to your client with the secret in an Authorization header. In Claude Code:
claude mcp add --transport http ds160 https://www.ds160.io/api/mcp --header "Authorization: Bearer ds160_sk_…"

Other clients take the same address and header in their settings. In Cursor (.cursor/mcp.json):

{
    "mcpServers": {
        "ds160": {
            "url": "https://www.ds160.io/api/mcp",
            "headers": { "Authorization": "Bearer ds160_sk_…" }
        }
    }
}

In VS Code (.vscode/mcp.json), add the same url and headers under "servers" with "type": "http". Keep the secret out of files you commit: use your client’s support for environment variables or secret inputs where it has one.

Connect claude.ai or ChatGPT

claude.ai and ChatGPT do not send a key. They connect by signing in to DS160.io instead:

  1. In claude.ai or ChatGPT, add https://www.ds160.io/api/mcp as a custom connector.
  2. When it asks, sign in to DS160.io with your own account.
  3. Pick the business workspace the agent will work in.
  4. Review the permissions it asks for, then click to allow.

The agent then acts as you, in that workspace. You must be an Owner or Admin of the workspace to allow a connection.

Scopes: what each allows

ScopeWhat the agent can do
forms:readList forms, read a form’s name and status, check what is missing, follow a run
forms:writeCreate forms (and read them)
forms:cloneCopy an existing form into a new one
client-links:writeCreate client links to send to applicants
answers:readRead a form’s answers
answers:writeWrite and remove a form’s answers
runs:writeStart a run at CEAC and follow it

answers:read sends applicants’ personal data out of DS160.io. Names, dates of birth, passport numbers, travel history and every other DS-160 answer the agent reads are passed to the agent and to whoever runs it, such as an AI provider. Your workspace, as the controller of its clients’ data, decides whether that is allowed, and is responsible for that data once it leaves DS160.io (see the privacy policy and the Data Processing Agreement). If the agent only needs to fill forms in, leave answers:read out: with answers:write alone it can write answers without reading them back.

What the agent can and cannot do

  • It can prepare a form: create it, fill in answers from what the client sent, see which questions are still missing or would be refused, and send the client a link for the rest.
  • Every answer it writes is checked as the form editor checks it. Text is stored in capitals unless the question allows letters outside English. An answer that does not fit is refused with a reason, and nothing else in the batch is affected.
  • Every change is recorded. The form’s Field history shows each change as “API key name” for a key, or as “member via agent” for a connection.
  • It cannot sign or submit. A run started by an agent always stops before signing, whatever the workspace’s setting: a person checks the application and signs it on CEAC (see Review Before Signing).
  • It cannot type CEAC’s captchas. A person types them in DS160.io while the run waits; the run tells the agent when someone is needed and where.
  • Creating a form is billed like creating one in the app: each form created, or cloned, counts as a form created.
  • It works only in its own workspace. It cannot see other workspaces, and a form from another workspace is reported as not found.

Tools

ToolWhat it doesScope
list_formsLists the workspace’s forms, newest firstforms:read
get_formReads one form’s name, status and consentforms:read
create_formCreates a form (billed per form created)forms:write
clone_formCopies a form into a new one, optionally leaving sections outforms:clone
create_client_linkCreates a client link for a formclient-links:write
search_docsSearches these docs, 200 searches a day per key or connectionany
describe_form_pagesLists the form’s pages and each question: its answer path, type, whether it is required, dropdown values and the questions each answer opens, with the JSON for each type of answerany
get_answersReads a form’s answers, for the whole form or one pageanswers:read
set_answersWrites up to 200 answers per call, in order: each is written, removed (value null) or refused with a code and reasonanswers:write
get_form_progressFor each section: its status, the required questions with no answer, and the problems by path; and whether the form is completeforms:read, answers:read or answers:write
start_runStarts a run at CEAC for a chosen consulate; stops before signingruns:write
get_runA run’s status, a summary of where it is, whether a person is needed, and the link to itruns:write or forms:read

Revoking access

  • A key: revoke it under Workspace Settings → Team & access → API Keys. The next call the agent makes is refused.
  • A connection (claude.ai, ChatGPT): revoke it in Account & Security, or for the whole workspace in Workspace Settings. Both list the connections that exist.

Revoke at once if a key may have leaked or an agent is no longer used.

Keep the agent to what the applicant gave

A DS-160 is signed by the applicant, who declares that every answer is true. Tell your agent to answer only from what the applicant gave you (their documents, emails and answers) and never to guess or make up an answer. Where it is not sure, it should leave the question empty, so that get_form_progress shows it as missing and the client or your staff answer it. Review the form before anyone signs it.

Troubleshooting

ProblemWhat to do
The client says it cannot connect, or gets 401Check the address is https://www.ds160.io/api/mcp and the header is Authorization: Bearer <secret>, with the whole secret. A revoked key cannot be used again: create a new one.
A tool says a scope is missingThe key or connection lacks that scope. Create a key with it (or connect again and allow it), then revoke the old one.
An answer is refusedRead its reason. Use describe_form_pages for the right path and the values a dropdown accepts.
start_run is refusedget_form_progress lists what is missing or wrong in each section. Fill it in, then start the run again. If a run of the form is already going, follow it with get_run.
The run waits with needsPersonSomeone opens the run’s link in DS160.io and types the captcha. Once the run is ready to sign, someone checks the application and signs it on CEAC.