Skip to main content
Glama
starlink-enterprise-mcp

starlink-enterprise-mcp

by WiFiWoW

Starlink Enterprise MCP Server

License: MIT TypeScript Starlink API MCP Protocol Cloud Run

πŸ›°οΈ Hosted, multi-account MCP for the Starlink Enterprise API Any AI agent β€” Claude, ChatGPT, anything that speaks MCP β€” connects with a real Starlink V2 Service Account, drives the full Enterprise API, and stays connected indefinitely. The Client Secret never touches the model.

⚑ Features

  • πŸ” Hosted OAuth proxy with API-key login β€” The server is the OAuth 2.1 authorization server. But Starlink has no interactive OAuth and no MFA, so the browser login page doesn't ask for a username and password β€” it asks for a Service Account Client ID + Client Secret. The server validates them with a client_credentials grant; credentials never enter the model's context.

  • πŸ” Transparent token re-minting β€” Starlink bearer tokens are short-lived (~15 min) and have no refresh token. The server stores the service-account credentials alongside the issued MCP token and silently re-mints a fresh bearer before expiry, and again on any 401. AI sessions stay alive across long conversations.

  • πŸͺ Stateless login state β€” OAuth pending state rides in HMAC-signed HttpOnly cookies, so logins survive container restarts and Cloud Run instance switches.

  • πŸ—„οΈ Firestore persistence β€” Issued tokens and DCR client registrations survive deploys and scaling events when MCP_PERSISTENCE=firestore.

  • 🀝 Claude and ChatGPT support β€” Public-client dynamic registration (token_endpoint_auth_method=none, PKCE only) means ChatGPT connects out of the box alongside confidential clients like Claude.

  • 🧬 55 auto-generated tools from the spec β€” The Starlink Enterprise v2 OpenAPI spec, regenerated on every build. Drop in a new spec and rebuild to pick up new endpoints.

  • 🎯 No curated layer needed β€” At 55 operations the full tool surface fits comfortably in a model's working memory, so every tool is exposed directly with read/write/destructive annotations.

  • ♾️ Stateless by default β€” No Mcp-Session-Id, no in-memory session map, no session affinity. Any instance can serve any request, so autoscaling and cold starts stop breaking mid-conversation.

  • 🧾 Typed results β€” Every tool declares an outputSchema derived from the OpenAPI response, and returns matching structuredContent. The model gets a typed object, not an opaque JSON blob.

  • πŸͺ› Operator-tunable β€” Disable globs (MCP_DISABLED_TOOLS=delete_*,*reboot*), a semantic destructive toggle (MCP_DISABLE_DESTRUCTIVE=true), branded login page (MCP_LOGIN_HEADER, MCP_ICON_URL). No code change for per-deployment policy.

  • πŸ§ͺ A real test suite β€” 108 tests, including a draft-2020-12 JSON Schema guard that compiles every tool's input and output schema on every run, and end-to-end JSON-RPC over the actual transport.

Related MCP server: agentforge

πŸ”‘ How auth differs from a username/password MCP

Username/password OAuth proxy

This server (Starlink)

Login page collects

username + password

Service Account Client ID + Client Secret

Upstream grant

password (+ MFA)

client_credentials

MFA

yes

none (service accounts skip MFA)

Refresh

upstream refresh token

re-run client_credentials (no refresh token)

Token TTL

hours

~15 min, re-minted on expiry / 401

The DCR + browser-redirect OAuth shell is identical β€” what changed is the login form and the upstream grant.

πŸ—οΈ Architecture

AI client (Claude/ChatGPT)
  β”‚  OAuth 2.1 DCR + browser login (PKCE)
  β–Ό
[ Starlink MCP HTTP server (this repo) ]   ← OAuth proxy, login page (Client ID + Secret), cookies, Firestore
  β”‚  per-account Starlink bearer (client_credentials)
  β–Ό
[ Starlink Enterprise API  https://www.starlink.com/api ]

Each issued MCP bearer maps to a stored upstream Starlink token plus the service-account credentials used to mint it, so the server can re-mint silently.

πŸ’» Running locally (stdio)

npm install
npm run build
export STARLINK_CLIENT_ID=<your-service-account-client-id>
export STARLINK_CLIENT_SECRET=<your-service-account-secret>
npm start                                      # MCP_TRANSPORT defaults to stdio

Create a V2 service account at Account Settings β†’ API V2 Service Accounts (requires the Admin or Service Account Management role).

Add this entry to your local MCP client config (Claude Desktop, etc.):

{
  "mcpServers": {
    "starlink": {
      "command": "node",
      "args": ["/path/to/starlink-enterprise-mcp/build/index.js"],
      "env": {
        "STARLINK_CLIENT_ID": "...",
        "STARLINK_CLIENT_SECRET": "..."
      }
    }
  }
}

You can also set STARLINK_ACCESS_TOKEN directly to skip the grant if you already hold a bearer.

🌐 Running as a hosted server (HTTP)

export MCP_TRANSPORT=http
export MCP_PORT=3000
export MCP_BASE_URL=https://mcp.example.com
export MCP_SESSION_SECRET=<32+ random hex>     # signs login-state cookies
npm start

Connect from Claude / ChatGPT by giving it the URL https://mcp.example.com/mcp. The client DCR-registers, redirects the user to /authorize, the user pastes their Service Account Client ID + Secret, and the bearer flows back to the AI automatically. No upstream operator credentials are needed in HTTP mode β€” each user brings their own service account.

Pass-through mode (credentials configured in the MCP client)

Set MCP_AUTH_MODE=passthrough and the connector supplies the Starlink Service Account as its OAuth client_id + client_secret (configured in Claude/ChatGPT, not on a login page). The server treats any presented client_id as a dynamic client, then at the /token exchange validates the client_secret against Starlink's client_credentials grant β€” a successful grant is the authentication. The credentials are then bound to that session and re-minted as usual. No login page, no server-side credentials, fully multi-tenant.

export MCP_AUTH_MODE=passthrough

In the client's connector setup, point it at https://…/mcp and enter your Starlink Service Account Client ID and Client Secret as the OAuth client credentials. Requirements: the client must use the authorization-code flow with PKCE and send the client_secret at the token endpoint (client_secret_post).

Single-account mode (skip the login page)

If you set STARLINK_CLIENT_ID + STARLINK_CLIENT_SECRET on the server, the /authorize step auto-logs-in with those and the credential-entry page is never shown β€” every user who connects shares that one Starlink account. Leave them unset for the multi-tenant login-page behavior above.

export STARLINK_CLIENT_ID=<service-account-id>
export STARLINK_CLIENT_SECRET=<service-account-secret>

Trade-off: in single-account mode the endpoint is only as private as its URL β€” DCR registration is open, so anyone who can reach /mcp and complete the (credential-free) OAuth flow uses that shared account. Put it behind access control, or accept that the URL is the secret.

☁️ Cloud Run deployment

Ships with a Cloud Run-friendly Dockerfile.

Component

Purpose

Cloud Run service

Runs the HTTP server. No session affinity or min-instances needed in the default stateless mode

Firestore (native mode)

Persistent token store and DCR client registry

Cloud Run SA β†’ roles/datastore.user

Firestore access

Pushes to main deploy through .github/workflows/deploy.yml, which runs the suite, builds the image in the runner, pushes it to Artifact Registry, and deploys it by digest. It then asserts the live revision is that digest, that an unauthenticated /mcp answers 401, and that pass-through advertises no registration_endpoint.

It does not use gcloud builds submit. That path stages a source tarball in the legacy gs://<project>_cloudbuild bucket and is refused under the external account credentials GitHub Actions federates with, whatever storage role the deploy identity holds.

To deploy by hand from a checkout instead:

image=<region>-docker.pkg.dev/<project>/cloud-run-source-deploy/starlink-enterprise-mcp
docker build -t "$image:$(git rev-parse HEAD)" .
docker push "$image:$(git rev-parse HEAD)"
gcloud run deploy starlink-enterprise-mcp --image "$image:$(git rev-parse HEAD)" \
  --region=<region> --project=<project> --port=3000

Required env vars on Cloud Run:

Var

Notes

MCP_TRANSPORT=http

enable the HTTP transport

MCP_BASE_URL

public URL, e.g. https://mcp.example.com

MCP_SESSION_SECRET

32+ chars; signs login-state cookies & must be stable across instances

MCP_PERSISTENCE=firestore

enable Firestore-backed tokens and clients

GOOGLE_CLOUD_PROJECT

Firestore project ID (auto-set on Cloud Run)

Transport and protocol options:

Var

Default

Notes

MCP_STATELESS

true

false restores Mcp-Session-Id sessions (single instance only)

MCP_JSON_RESPONSE

false

Return plain JSON instead of SSE, for intermediaries that break event streams

MCP_ALLOWED_ORIGINS

unset

Comma-separated allowlist; a non-matching Origin gets 403

MCP_STRUCTURED_OUTPUT

true

false drops outputSchema and structuredContent together

MCP_TOOLS_PAGE_SIZE

0 (one page)

Page size for tools/list cursor pagination

MCP_TASKS

false

Enable task augmentation (see above)

MCP_TASKS_COLLECTION

mcp_tasks

Firestore collection for task state

MCP_WEBSITE_URL

Starlink API docs

websiteUrl advertised at initialize

Also optional: STARLINK_API_URL, STARLINK_TOKEN_URL (defaults are correct for production), MCP_LOGIN_HEADER, MCP_ICON_URL, MCP_LOGIN_LOGO_URL, MCP_DISABLED_TOOLS, MCP_DISABLED_ACTIONS, MCP_DISABLE_DESTRUCTIVE, MCP_CORS_ORIGIN.

MCP_ICON_URL now does double duty: it still serves the favicon and login-page logo, and it is also advertised as the server's MCP icons entry so clients can render it in a connector list.

Other targets: fly.toml (Fly.io), render.yaml (Render), railway.toml (Railway), docker-compose.yml, and k8s/ manifests (apply with kubectl apply -k k8s/).

Security note on persistence. In HTTP mode the issued-token records hold each user's Starlink service-account Client ID + Secret so the server can re-mint bearers. Protect the token store accordingly β€” restrict the Firestore collection / file volume, and rotate MCP_SESSION_SECRET and service-account secrets per Starlink's guidance if exposure is suspected.

πŸ” OAuth flow (detailed)

  1. AI client hits GET /.well-known/oauth-protected-resource/mcp and /.well-known/oauth-authorization-server for discovery.

  2. AI client POSTs /register (RFC 7591 DCR). Public clients pass token_endpoint_auth_method=none and get back a client_id only; confidential clients also get a client_secret. Registrations persist in Firestore.

  3. AI redirects the user's browser to /authorize?... with PKCE parameters. The server stores the pending request in a signed cookie (mcp_pending_auth, 15 min TTL) and renders the login page.

  4. User submits their Service Account Client ID + Client Secret β†’ server runs POST {STARLINK_TOKEN_URL} with grant_type=client_credentials. On success it stores the Starlink token + credentials and issues an authorization code.

  5. The server redirects back to the AI client; cookies are cleared.

  6. AI exchanges the code at /token for the MCP-issued bearer + refresh token.

  7. On every /mcp request, the server verifies the bearer and transparently re-mints the upstream Starlink token if it's near expiry. On a 401 from the API, the client re-mints and retries once.

πŸ“ MCP spec conformance

Targets MCP 2025-11-25 and negotiates down to any revision the client asks for (2025-06-18, 2025-03-26, 2024-11-05).

Feature

Revision

Status

Streamable HTTP, stateless

2025-03-26

Default. MCP_STATELESS=false for sessions

MCP-Protocol-Version header validation

2025-06-18

Unsupported version β†’ 400

Structured output (outputSchema / structuredContent)

2025-06-18

52 of 55 tools; MCP_STRUCTURED_OUTPUT=false to disable

Tool title display names

2025-06-18

All tools

OAuth Resource Server + protected-resource metadata

2025-06-18

RFC 9728 discovery, WWW-Authenticate

No JSON-RPC batching

2025-06-18

Not accepted

Icons on server and tools

2025-11-25 (SEP-973)

From MCP_ICON_URL

Implementation.description, title, websiteUrl

2025-11-25

Sent at initialize

Invalid Origin β†’ 403

2025-11-25

Via MCP_ALLOWED_ORIGINS

Validation errors as tool errors, not protocol errors

2025-11-25 (SEP-1303)

Arguments validated, types coerced

Tool-name format guidance

2025-11-25 (SEP-986)

Validated at startup

JSON Schema 2020-12 as default dialect

2025-11-25 (SEP-1613)

Input and output schemas

Tasks (durable requests, polling, deferred results)

2025-11-25 (SEP-1686)

Opt-in via MCP_TASKS=true

tools/list cursor pagination

2024-11-05

Opt-in via MCP_TOOLS_PAGE_SIZE

logging capability + logging/setLevel

2024-11-05

Supported

Not implemented, and why: resources and prompts (this server exposes an API surface, not documents or templates), completions (nothing to complete without prompts or resource templates), sampling, elicitation, and roots (client-side features this server has no use for β€” every tool call is fully specified by its arguments).

Stateless vs. session mode

Stateless is the default. Each request gets a fresh Server and transport, and no Mcp-Session-Id is issued.

This matters on any autoscaled host. With sessions, initialize builds in-memory state on one instance, and the next tools/call gets load-balanced to an instance that has never heard of that session ID β€” the client sees Invalid or missing session ID and the conversation dies. Stateless has no affinity requirement, so min-instances=1 and session affinity stop being load-bearing.

Nothing is given up here: this server sends no server-initiated messages. The tool list is fixed at build time from the OpenAPI spec, and there are no resources or prompts to subscribe to, so the standalone GET /mcp SSE stream that sessions exist to support has nothing to carry. In stateless mode it answers 405 rather than opening a stream that can never produce anything.

Set MCP_STATELESS=false on a single-instance deployment to restore sessions.

Tasks

Off by default. A task-augmented tools/call returns a handle immediately and the client collects the result later via tasks/result, decoupling the tool's runtime from the HTTP request's lifetime.

Enabling it on Cloud Run needs two things that are not the default:

  • --no-cpu-throttling, or the container is frozen once the response is sent and the detached work never finishes.

  • MCP_PERSISTENCE=firestore, or the poll lands on an instance that has never heard of the task. With Firestore the store is shared and any instance can answer. Without it you get an in-memory store and a startup warning.

export MCP_TASKS=true
export MCP_PERSISTENCE=firestore     # required for more than one instance

Task documents live in mcp_tasks (override with MCP_TASKS_COLLECTION) and carry an expiresAt field β€” set a Firestore TTL policy on it to have Firestore reclaim them. Client-requested TTLs are clamped to 24 hours.

🧰 Tools

55 tools generated from spec/starlink-enterprise-v2.json, grouped by tag:

Group

Examples

Account

get_account, get_products, post_data_usage_query

Service Lines

get_service_lines, post_service_lines, put_service_line_nickname, post_service_line_data_top_up, patch_service_line_consume_from_pool

User Terminals

get_user_terminals, post_user_terminals, post_user_terminal_reboot, put_user_terminal_l2vpn

Routers

get_router, get_routers_configs, post_routers_configs, post_router_reboot, *_routers_configs_tls

Addresses

get_addresses, post_addresses, get_address, put_address

Contacts

get_contacts, post_contacts, put_contact, delete_contact

Data Pools

get_data_pools, get_data_pools_usage, post_data_pools_by_data_pool_id_set_automatic_top_up

Flights

post_flights_status (aviation accounts)

Managed

post_managed_customers (provider accounts)

Each tool carries a human-readable title, an inputSchema, an outputSchema, and the full annotation set: readOnlyHint, destructiveHint, idempotentHint (GET/PUT/DELETE), and openWorldHint. Reboots and deletes are flagged destructive β€” hide them all with MCP_DISABLE_DESTRUCTIVE=true, or selectively with e.g. MCP_DISABLED_TOOLS=delete_*,*reboot*.

Tool names map 1:1 to operations ({method}_{path}, with the /public/v2 prefix stripped). Two deep service-line paths are abbreviated to fit the MCP 64-character name limit.

Result shape

Results carry structuredContent matching the tool's outputSchema, shaped like the Starlink response envelope β€” payload under content, plus isValid:

{
  "content": [{ "type": "text", "text": "{ \"content\": { \"accountNumber\": \"ACC-…\" } }" }],
  "structuredContent": { "content": { "accountNumber": "ACC-…", "regionCode": "US" }, "isValid": true }
}

The schemas are deliberately permissive: no required, no additionalProperties: false, and nullable fields widened to a type union. A Starlink response that has drifted from the published spec still validates rather than being rejected by a strict client. If a client is still unhappy, MCP_STRUCTURED_OUTPUT=false drops both the schemas and the structured results in one move.

Errors come back in the result, not as protocol errors. A permission failure, a bad argument, or an operator-disabled tool returns isError: true with an explanatory message, so the model can read what went wrong and retry. Only an unknown tool name is a JSON-RPC error. Arguments are validated against the input schema before any call is made, and obvious type mismatches ("50" for a number) are coerced rather than rejected.

πŸ”„ Regenerating tools

The spec lives at spec/starlink-enterprise-v2.json (sourced from https://web-api.starlink.com/enterprise/swagger/v2/swagger.json). That host now serves Starlink's consumer web app and no longer carries this path, and the new spec location is not known. Do not guess a replacement URL. To refresh once a real source turns up:

# drop a new spec into spec/starlink-enterprise-v2.json, then:
npm run generate      # rewrites src/generated/
npm run build
npm test

npm run build runs generate automatically via the prebuild hook.

πŸ§ͺ Tests

npm test

The Firestore-backed tests are emulator-gated and skip cleanly without one.

πŸ“‹ What this server is

  • Two MCP transports. stdio for local CLI integrations and http (Streamable HTTP, stateless by default) for hosted deployments. Production uses http.

  • MCP 2025-11-25, negotiating down to older revisions on request.

  • Auto-generated tools from the Starlink Enterprise v2 OpenAPI spec, regenerated on every build, with typed structuredContent results.

  • Hosted OAuth login where the login page collects Starlink Service Account credentials (Client ID + Secret), not a username/password. MFA does not apply to service accounts.

  • Transparent token re-minting via client_credentials (no refresh token).

  • Firestore persistence for tokens and DCR clients when MCP_PERSISTENCE=firestore.

License

MIT

Available Tools

55 tools
delete_contacts_by_subject_idA
Destructive

Delete contact β€” Required permission: Admin Only - API User Management, Edit.Deletes contact based on specified subject Id on the authenticated account. β€” [DELETE /public/v2/contacts/{subjectId}]

Inputs: subjectId (required).

delete_routers_configs_tlsA
Destructive

Delete TLS config β€” Required permission: Device command and configuration, Edit.Deletes a TLS certificate and key pair from the set of TLS configs that can be reused when saving router configs and only specifying the certificate. Does not affect any router configs that were already saved, just removes it from list of certificates that the matching key will be inserted on save for. β€” [DELETE /public/v2/routers/configs/tls]

Inputs: certificateBase64Pem (required).

delete_service_lines_by_service_line_numberB
Destructive

Deactivate a service line β€” Required permission: Service plan, Edit. β€” [DELETE /public/v2/service-lines/{serviceLineNumber}]

Inputs: serviceLineNumber (required), reasonForCancellation, endNow.

delete_service_line_user_terminalA
Destructive

Remove user terminal from service line β€” Required permission: Service plan, Edit.This removes the user terminal from the service line, but it remains on the account and can be added to another service line. This clears any L2VPN circuits configured for the terminal. β€” [DELETE /public/v2/service-lines/{serviceLineNumber}/user-terminals/{deviceId}]

Inputs: serviceLineNumber (required), deviceId (required).

delete_user_terminals_by_device_idA
Destructive

Remove user terminal from account β€” Required permission: Device management, Edit.User terminal must already be removed from service lines before it can be removed from the account. See /v2/service-lines/{serviceLineNumber}/user-terminals/{deviceId} β€” [DELETE /public/v2/user-terminals/{deviceId}]

Inputs: deviceId (required).

get_accountA
Read-only

Get account information β€” Required permission: Account information, View. β€” [GET /public/v2/account]

Inputs: no named parameters.

get_addressesA
Read-only

Get all addresses β€” Required permission: Account information, View.Returns all addresses on the account in paginated form. β€” [GET /public/v2/addresses]

Inputs: addressIds, metadata, page.

get_addresses_by_address_reference_idA
Read-only

Get address β€” Required permission: Account information, View. β€” [GET /public/v2/addresses/{addressReferenceId}]

Inputs: addressReferenceId (required).

get_contactsA
Read-only

Get contacts β€” Required permission: User management, Edit.Get list of contacts on the authenticated user's account. β€” [GET /public/v2/contacts]

Inputs: page.

get_data_poolsA
Read-only

Pre-Release: Get all multi-service line enabled data pools. β€” Required permission: Service plan, View.This endpoint is available for select audiences only. β€” [GET /public/v2/data-pools]

Inputs: productReferenceId, dataPoolIds, page.

get_data_pools_usageA
Read-only

Pre-Release: Query data pool usage with service line and monthly breakdowns. β€” Required permission: Service plan, View.This endpoint is available for select audiences only. β€” [GET /public/v2/data-pools/usage]

Inputs: dataPoolIds, asOfTimestamp, page, limit.

get_productsA
Read-only

Get products β€” Required permission: Service plan, View.Gets all products available to this account that could be assigned to service lines. Each product includes data block product info if compatible. β€” [GET /public/v2/products]

Inputs: page.

get_routers_by_router_idA
Read-only

Get router β€” Required permission: Device management, View. β€” [GET /public/v2/routers/{routerId}]

Inputs: routerId (required).

get_routers_configsA
Read-only

Get all router configs β€” Required permission: Device command and configuration, View.Return all router configs on this account in paginated form β€” [GET /public/v2/routers/configs]

Inputs: page.

get_routers_configs_by_config_idB
Read-only

Get router config β€” Required permission: Device command and configuration, View. β€” [GET /public/v2/routers/configs/{configId}]

Inputs: configId (required).

get_routers_configs_defaultA
Read-only

Get default router config β€” Required permission: Device command and configuration, View.Gets the router config id that will be assigned to any routers when they are first added to this account. β€” [GET /public/v2/routers/configs/default]

Inputs: no named parameters.

get_routers_configs_tlsA
Read-only

Get TLS configs β€” Required permission: Device command and configuration, View.Gets a paginated list of TLS configs on this account. β€” [GET /public/v2/routers/configs/tls]

Inputs: page.

get_routers_local_contentA
Read-only

Get list of router local content files β€” Required permission: Device command and configuration, View. β€” [GET /public/v2/routers/local-content]

Inputs: no named parameters.

get_routers_sandbox_clientsA
Read-only

Get sandbox clients β€” Required permission: Device command and configuration, View.Returns clients that were unsandboxed through the management API and have access that has not yet expired, paginated 1000 at a time. Clients that are allowed internet access due to sandbox disablement are not returned. β€” [GET /public/v2/routers/sandbox/clients]

Inputs: sandboxId, expiryAfter, page.

get_service_line_billing_cycles_partial_periodsA
Read-only

Get billing partial periods β€” Required permission: Service plan, View.Get the previous billing partial periods for this service line. For more information about this endpoint, see https://starlink.readme.io/docs/understanding-proration. β€” [GET /public/v2/service-lines/{serviceLineNumber}/billing-cycles/partial-periods]

Inputs: serviceLineNumber (required).

get_service_linesA
Read-only

Get all service lines β€” Required permission: Service plan, View. β€” [GET /public/v2/service-lines]

Inputs: addressReferenceId, searchString, dataPoolId, page, +1 more.

get_service_lines_by_service_line_numberA
Read-only

Get service line β€” Required permission: Service plan, View. β€” [GET /public/v2/service-lines/{serviceLineNumber}]

Inputs: serviceLineNumber (required).

get_user_terminalsA
Read-only

Get all user terminals β€” Required permission: Device management, View.Gets all user terminals on the account, filtered by the optional filter parameters, in paginated form β€” [GET /public/v2/user-terminals]

Inputs: serviceLineNumbers, userTerminalIds, hasServiceLine, searchString, +1 more.

get_user_terminals_l2vpnA
Read-only

Get L2VPN circuits available for this account β€” Required permission: Device command and configuration, View. β€” [GET /public/v2/user-terminals/l2vpn]

Inputs: no named parameters.

patch_service_lines_by_service_line_number_consume_from_poolA

Pre-Release: Set whether a service line should consume from a data pool. β€” Required permission: Service plan, Edit.This endpoint is available for select audiences only. β€” [PATCH /public/v2/service-lines/{serviceLineNumber}/consume-from-pool]

Inputs: serviceLineNumber (required), consumeFromPool.

post_addressesC

Create address β€” Required permission: Account information, Edit. β€” [POST /public/v2/addresses]

Inputs: addressLines (required), administrativeAreaCode (required), regionCode (required), formattedAddress (required), +7 more.

post_contactsB

Create contact β€” Required permission: Admin Only - API User Management, Edit.Creates the contact if it is new, and adds the contact to the authenticated account. β€” [POST /public/v2/contacts]

Inputs: firstName (required), lastName (required), roles (required), email (required), +2 more.

post_data_pools_by_data_pool_id_set_automatic_top_upB

Pre-Release: Enable or disable automatic top-up for a data pool. β€” Required permission: Service plan, Edit.This endpoint is available for select audiences only. β€” [POST /public/v2/data-pools/{dataPoolId}/set-automatic-top-up]

Inputs: dataPoolId (required), enabled.

post_data_usage_queryC

Query data usage β€” Required permission: Service plan, View.Retrieve the real-time data tracking info for this account's data usage. For detailed instructions, please refer to the API documentation: https://starlink.readme.io/docs/data-usage-api β€” [POST /public/v2/data-usage/query]

Inputs: page, limit, serviceLineNumbers, previousBillingCycles, +2 more.

post_flights_statusB

Post a flight event β€” Required permission: Aviation flight status management, Edit.Post a real-time flight event on a Starlink-enabled plane. This endpoint is only accessible from an aviation account. β€” [POST /public/v2/flights/status]

Inputs: tailNumber (required), flightNumber (required), eventType (required), eventTimeUtc, +5 more.

post_managed_customersA

Create a managed customer account β€” This endpoint is only callable with an authorized provider account. β€” [POST /public/v2/managed/customers]

Inputs: firstName (required), lastName (required), email (required), phone (required), +2 more.

post_routers_by_router_id_rebootA
Destructive

Reboot router β€” Required permission: Device command and configuration, Edit. β€” [POST /public/v2/routers/{routerId}/reboot]

Inputs: routerId (required).

post_routers_configsB

Create router config β€” Required permission: Device command and configuration, Edit. β€” [POST /public/v2/routers/configs]

Inputs: routerConfigJson (required), nickname.

post_routers_configs_tlsA

Create TLS config β€” Required permission: Device command and configuration, Edit.Creates a TLS config that allows this certificate and key to be used in router configs when a certificate and key are required by only specifying the certificate (matching key will be added). TLS configs are identified by their certificate string base64 encoded which must be unique on the account. β€” [POST /public/v2/routers/configs/tls]

Inputs: certificateBase64Pem (required), keyBase64Pem (required).

post_routers_local_contentA

Upload router local content file β€” Required permission: Device command and configuration, Edit.Upload html file to allow it to be configured as the HTTPS server local content file for router configs. File must be HTML, under 4MB, and file name under 100 characters. Files are stored in a public bucket for configured routers to download. File should be attached as multipart/form-data. See https://starlink.readme.io/docs/local-content for example upload script. β€” [POST /public/v2/routers/local-content]

Inputs: File (required).

post_routers_sandbox_clientsA

Batch update sandbox clients β€” Required permission: Device command and configuration, Edit.Update the sandbox state for multiple clients. If sandboxing is enabled, sandboxed clients will only have access to domains in the sandbox domain allow list. If a client is duplicated, records the client with the latest expiry. β€” [POST /public/v2/routers/sandbox/clients]

Inputs: no named parameters.

post_service_linesA

Create service line β€” Required permission: Service plan, Edit.Service line must be linked to an address and a subscription/product-ID, and can optionally be immediately configured with data blocks. β€” [POST /public/v2/service-lines]

Inputs: addressReferenceId (required), productReferenceId (required), dataBlockProducts.

post_service_lines_by_service_line_number_data_opt_inA

Opt in priority data β€” Required permission: Service plan, Edit.Opt in the service line to continue using priority data after reaching the plan capacity. Only applies to some products. β€” [POST /public/v2/service-lines/{serviceLineNumber}/data/opt-in]

Inputs: serviceLineNumber (required).

post_service_lines_by_service_line_number_data_opt_outA

Opt out priority data β€” Required permission: Service plan, Edit.Opt out the service line from continuing to use priority data even when plan capacity is exceeded. If the service line reaches the plan capacity, it will switch to using standard data. Only applies to some products. β€” [POST /public/v2/service-lines/{serviceLineNumber}/data/opt-out]

Inputs: serviceLineNumber (required).

post_service_lines_by_service_line_number_data_top_upA

Adds one-time top up data block to service line β€” Required permission: Service plan, Edit.Service line must be on a top up plan β€” [POST /public/v2/service-lines/{serviceLineNumber}/data/top-up]

Inputs: serviceLineNumber (required), productId (required), count (required).

post_service_lines_by_service_line_number_user_terminalsA

Add user terminal to service line β€” Required permission: Service plan, Edit.User terminal must already be on the account. See POST /v2/user-terminals to add user terminal to account. β€” [POST /public/v2/service-lines/{serviceLineNumber}/user-terminals]

Inputs: serviceLineNumber (required), deviceId (required).

post_user_terminalsA

Add user terminal to account β€” Required permission: Device management, Edit.This will add the user terminal to the account, but won't start service. User terminals must be present on the account before adding to a service line. β€” [POST /public/v2/user-terminals]

Inputs: deviceId (required).

post_user_terminals_by_device_id_rebootC
Destructive

Reboot user terminal β€” Required permission: Device command and configuration, Edit. β€” [POST /public/v2/user-terminals/{deviceId}/reboot]

Inputs: deviceId (required).

put_addresses_by_address_reference_idB

Update address β€” Required permission: Account information, Edit. β€” [PUT /public/v2/addresses/{addressReferenceId}]

Inputs: addressReferenceId (required), addressLines (required), administrativeAreaCode (required), regionCode (required), +8 more.

put_contacts_by_subject_idB

Update contact β€” Required permission: Admin Only - API User Management, Edit.Update contact on the authenticated account. β€” [PUT /public/v2/contacts/{subjectId}]

Inputs: subjectId (required), roles, phoneNumber.

put_routers_configs_assignA

Router config assignment β€” Required permission: Device configuration assignment, Edit.Assign the config (or none) to the routers. For each router if it is currently online, the config will immediately be sent to the router. Else, the config will be sent to the router when it comes online. Configs are sent to the router within 1-2 minutes. On error no assignment occurs. β€” [PUT /public/v2/routers/configs/assign]

Inputs: routerIds (required), configId.

put_routers_configs_by_config_idA

Update router config β€” Required permission: Device command and configuration, Edit.Update a given router config. Any router assigned to this config will immediately receive the update if it is online. Otherwise, the router will receive the update when it comes online. β€” [PUT /public/v2/routers/configs/{configId}]

Inputs: configId (required), routerConfigJson (required), nickname.

put_routers_configs_defaultA

Set default router config β€” Required permission: Device configuration assignment, Edit.Set the default router config on the account. Use an empty string to remove the default config from the account. Any NEW routers on this account will be assigned this config. β€” [PUT /public/v2/routers/configs/default]

Inputs: configId (required).

put_routers_sandbox_heartbeatA

Update sandbox heartbeat β€” Required permission: Device command and configuration, Edit.Heartbeats verify the health of enterprise systems that manage router sandboxing. If heartbeats are not received for an account, Starlink API will instruct routers under the account disable sandboxes until reboot. β€” [PUT /public/v2/routers/sandbox/heartbeat]

Inputs: healthy (required).

put_service_lines_by_service_line_number_data_recurringA

Set recurring data blocks on service line β€” Required permission: Service plan, Edit.Service line must be on a top up plan β€” [PUT /public/v2/service-lines/{serviceLineNumber}/data/recurring]

Inputs: serviceLineNumber (required), recurringDataBlocks, dataPoolId, applyToCurrentMonth.

put_service_lines_by_service_line_number_nicknameB

Set service line nickname β€” Required permission: Service plan, Edit. β€” [PUT /public/v2/service-lines/{serviceLineNumber}/nickname]

Inputs: serviceLineNumber (required), nickname (required).

put_service_lines_by_service_line_number_productC

Update service line product β€” Required permission: Service plan, Edit. β€” [PUT /public/v2/service-lines/{serviceLineNumber}/product]

Inputs: serviceLineNumber (required), productReferenceId (required), recurringDataBlocks, dataPoolId, +1 more.

put_service_lines_by_service_line_number_public_ipA

Set service line public IP setting β€” Required permission: Device command and configuration, Edit.Enable or disable public ip setting on a service line β€” [PUT /public/v2/service-lines/{serviceLineNumber}/public-ip]

Inputs: serviceLineNumber (required), publicIp (required).

put_user_terminals_by_device_id_l2vpnB

Set L2VPN VLANs for user terminal β€” Required permission: Device configuration assignment, Edit.Terminal must be on subscription that allows L2VPN. Maximum 2 circuits per Starlink PoP. Use null or empty circuit list to clear all L2VPN circuits for terminal. See /user-terminals/available-circuits for all configurable circuits and associated Starlink PoP. β€” [PUT /public/v2/user-terminals/{deviceId}/l2vpn]

Inputs: deviceId (required).

put_user_terminals_configs_assignA

User terminal config assignment β€” Required permission: Device configuration assignment, Edit.Assign the config (or none) to the user terminals. For each terminal if it is currently online, the config will immediately be sent. Else, the config will be sent when it comes online. On error no assignment occurs. Currently terminal configIds are only visible on starlink website. β€” [PUT /public/v2/user-terminals/configs/assign]

Inputs: userTerminalIds (required), configId.

Tool Schema Changelog

Recent tool additions, removals, and schema changes observed during successful MCP inspections.

Loading tool schema changelog…

    TDQS

    A3.5/5.0

    Scored across 55 tools

    Disambiguation4/5

    Most tools have distinct resource and action combinations, making them easily distinguishable. Overlaps are minimal, e.g., between list and single-resource getters, but descriptions clarify.

    Naming Consistency4/5

    The naming generally follows a verb_resource_by_identifier pattern, but there are a few outliers like 'post_data_usage_query' and 'put_routers_sandbox_heartbeat' that break the pattern. Overall, it is mostly consistent.

    Tool Count3/5

    With 55 tools, the server is comprehensive but could be considered heavy for typical use. The count is justified by the broad scope of enterprise management, but it borders on too many.

    Completeness4/5

    The tool set covers CRUD and additional operations for most core entities (account, service lines, user terminals, routers, data). Minor gaps exist, such as a single flight endpoint, but the primary domain is well-covered.

    Maintenance

    ActivitySlowing
    ResponsivenessNo recent community issues

    Related MCP Connectors

    Related MCP Servers

    • A
      license
      Not graded
      quality
      C
      maintenance
      A production-ready MCP server that provides secure, delegated access to Microsoft 365 services including Email, SharePoint, OneDrive, and Calendar. It enables AI models to search messages, browse files, manage calendar events, and parse document contents using OAuth 2.1 authentication.
      MIT
    • A
      license
      A
      quality
      D
      maintenance
      MCP server that exposes 300+ AI agents as tools via a single API key. Supports listing agents, invoking any agent with chat-completion style messages, checking agent health, and retrieving platform statistics.
      5
      4
      MIT