Use the MCP server with API tokens for agentic workflows
Scheduled jobs, agents in chat tools, and other unattended workflows cannot complete a browser sign-in, and an OAuth session eventually needs a person to sign in again. For these workflows, connect to the JupiterOne remote MCP server with a JupiterOne API token. The agent sends the token on every request, so the connection keeps working without anyone present until the token expires or you revoke it.
Use OAuth when a person works with the assistant interactively. Use an API token when the assistant runs on its own.
Prerequisites
- Your JupiterOne account ID, found in Account Management
- Your JupiterOne region (
usoreu) - An AI client that can send a custom HTTP header to a remote MCP server
- For an account-level API token, the account administrator role
Choose a token type
The remote MCP server accepts both kinds of JupiterOne API token. Choose the one that matches how the workflow should be identified.
| Detail | Account-level API token | User API token |
|---|---|---|
| Acts as | The token itself—it has no user | The user who created it |
| Permissions | Set on the token when you create it | The user's roles and groups |
| Created in | Settings > Account API tokens (administrators) | Settings > User API Tokens |
| Lifetime | 1 to 365 days, set at creation | Capped by the account's maximum token age, when one is set |
| Best for | A service account for one workflow | A workflow that must act as a specific person |
Account-level API tokens are usually the better fit for agentic workflows: each workflow gets its own token with only the permissions it needs, and nothing depends on a person's account.
Create an account-level API token
- Navigate to Settings > Account API tokens.
- Click New token.
- Enter a Name that identifies the workflow, for example
Nightly exposure report agent. - Enter Days before expiration. Choose the shortest lifetime the workflow can tolerate, and plan to rotate the token before it expires.
- Under Permissions, select only what the workflow needs. A reporting or triage agent typically needs read access only.
- Optionally, use Resource permissions to limit the token to specific resources.
- Save the token and copy its value. Store it in your secret manager; you need it to configure the agent.
To let the agent see the token's own permissions when it tests the connection, include the read level of Full Admin Access (fullReadAccess). Without it, the connection still works, but the agent cannot list the token's permissions.
To use a user API token instead, create it in Settings > User API Tokens while signed in as the user the workflow should act as.
Build the server URL
The URL must name your account by its account ID. Use either form:
https://<accountId>.mcp.<region>.jupiterone.io/mcp
https://mcp.<region>.jupiterone.io/mcp?accountId=<accountId>
Replace <region> with us or eu, and <accountId> with your account ID exactly as it appears in Account Management. Most account IDs are UUIDs; some older accounts have a readable ID instead. Do not use your vanity domain. The URL without an account, https://mcp.<region>.jupiterone.io/mcp, does not accept API tokens.
Configure your agent
Every request must carry the token in the Authorization header with the Bearer scheme:
Authorization: Bearer <your-api-token>
Include the word Bearer and a space before the token. A token sent in another header, without Bearer, or in the URL is not accepted.
Claude Code
Add the server with the header:
claude mcp add --transport http jupiterone \
"https://<accountId>.mcp.us.jupiterone.io/mcp" \
--header "Authorization: Bearer $JUPITERONE_API_TOKEN"
To read the token from a secret store each time Claude Code connects, use headersHelper in .mcp.json instead of a fixed header. The helper command must print a JSON object of headers:
{
"mcpServers": {
"jupiterone": {
"type": "http",
"url": "https://<accountId>.mcp.us.jupiterone.io/mcp",
"headersHelper": "echo '{\"Authorization\": \"Bearer '\"$(get-jupiterone-token)\"'\"}'"
}
}
}
Replace get-jupiterone-token with the command that reads the token from your secret store. Claude Code runs the helper again when the server rejects a request, so a rotated token is picked up without a restart.
Claude and Claude in Slack
When you add the JupiterOne connector, enter the server URL, then add a custom header:
- Name:
Authorization - Value:
Bearer <your-api-token>
If the connector restricts network access, allow the MCP server host. An API token connection only calls the /mcp path.
Microsoft Copilot Studio
- On the agent's Tools page, select Add a tool > New tool > Model Context Protocol.
- Enter a name, a description, and the server URL.
- Select API key as the authentication type, Header as the type, and enter
Authorizationas the header name. - When you create the connection, enter the key as
Bearer <your-api-token>.
Copilot Studio does not list tools whose inputs use reference types, so create-inline-question-rule and update-inline-question-rule are not available there.
Other clients
Most MCP clients that connect to remote servers accept a headers setting next to the URL. Use the same URL and Authorization header shown above.
Verify the connection
Ask the agent to run test-connection. A working connection reports connected: true, the account, and how the credential was identified:
credential.type: "account_token"—an account-level token, with itsname,expiresAt, and the permissions set on it inpermissions.grantedcredential.type: "user"—a user API token, with the user's email and a summary of their permissionscredential.type: "userless_token"—an API token with no user whose permissions the agent cannot see.credential.noteexplains why, most often that the token lacksfullReadAccess.
To find its own entry, an account-level token with fullReadAccess reads the account's token list each time it runs test-connection. Each read records a list tokens event in the audit log under that token, so a service account that tests its connection regularly shows repeated list tokens events.
Run workflows safely
- Give each workflow its own token. Name the token after the workflow so you can revoke one without affecting others.
- Grant the minimum permissions. Agents that read untrusted data, such as alert text or asset metadata from external sources, can be steered by that data. A read-only token limits what a misled agent can change.
- Set an expiry and rotate. Track expiry dates and replace tokens before they lapse. Revoking a token in JupiterOne takes effect on the MCP server within about six minutes.
- Keep the token secret. Store it in a secret manager and inject it at run time. Never put it in a URL, a prompt, or source control.
- Create Account dashboards. An account-level token has no user, so it cannot own a personal (User) dashboard. Ask the agent to create Account dashboards instead.
- Plan for long queries. Each MCP request has a time limit of about 55 seconds. A long-running J1QL query returns a handle instead of results, and the agent retrieves the results with
get-query-results. - Watch your rate limits. Every MCP request counts against your API rate limits.
Accounts that restrict access with an IP allowlist cannot use the remote MCP server. Do not add the MCP server's addresses to your allowlist to make it work: every request through the MCP server comes from those addresses, so anyone holding a valid token for your account could reach it through the MCP server from anywhere.
Troubleshooting
| Response | Cause | Fix |
|---|---|---|
400 "API tokens need the account ID in the URL" | The URL has no account | Use one of the URL forms in Build the server URL |
400 "not a JupiterOne API token" | The header value is not a token, for example Bearer appears twice or the value has spaces | Send Authorization: Bearer <your-api-token> with the token exactly as issued |
401 "Authorization header must use the Bearer scheme" | The token was sent without Bearer | Add Bearer before the token |
401 "API token rejected" | The token is invalid, revoked, or expired, or the URL names a different account than the token's | Check the token, and check that the account ID in the URL is the token's account |
401 "API token belongs to a different account" | The token is valid for another account | Use the URL for the token's account |
403 | JupiterOne refused the request for the account, for example because of an IP allowlist | See the IP allowlist warning above |
503 "retry shortly" | The token could not be checked | Retry the request |
A rejected token stays rejected for about 15 seconds. Wait before you retry with the same token.