Gcore MCP Server
OfficialThis server exposes the full Gcore API (~820 operations) to an MCP client through search, schema inspection, risk-separated call tools, and sandboxed Python.
Search Gcore API operations using plain language or resource paths.
Retrieve exact argument schemas and result fields for any operation.
Run read-only operations without approval.
Run write operations that create or change resources, with confirmation.
Run destructive operations such as deletes, overwrites, and interrupts, with confirmation.
Execute short sandboxed Python scripts to chain multiple read calls, loop, filter, and join results without intermediate data entering the conversation.
Work across Gcore Cloud, CDN, DNS, WAAP, Storage, Streaming, FastEdge, IAM, and Security.
Manage cloud projects/regions, list resources, create SSH keys, delete DNS records, upload FastEdge
.wasmfiles, and more.Enforce safety controls including read-only mode, deny-lists, approval/token flows, and risk hints.
Use dynamic mode with 6 tools to reach all operations, or direct mode for selected operations as individual tools.
Provides tools for managing Gcore Cloud resources including virtual instances, bare metal servers, GPU clusters, networking, security, storage, AI/ML, billing, containers, and DNS operations via the Gcore API.
Click on "Deploy Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@Gcore MCP Server list my virtual machines"
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
Gcore MCP Server
An MCP (Model Context Protocol) server for the whole Gcore API: Cloud, CDN, DNS,
WAAP, Storage, Streaming, FastEdge, IAM and Security. It is generated from the
official gcore Python SDK, so every operation
the SDK has (about 820 of them) is available, and upgrading the SDK is a version bump.
Small context cost. By default the model sees 6 tools (~1.3k tokens) instead of ~820 tools (~440k tokens), and still reaches every operation.
Safe by default. Destructive calls need your approval. There is also a read-only mode and a deny-list, and every tool carries read-only/destructive hints.
Built for models. Plain-language search, exact argument schemas with docs, readable errors with hints, compact results, and sandboxed Python for multi-step tasks.
Building FastEdge apps? Use the gcore-fastedge plugin (or the FastEdge MCP server): it scaffolds, builds, deploys and tests Wasm apps. This server manages what is already built, FastEdge included.
Quickstart
You need uv and a
Gcore API key.
Keep the key out of config files and shell history. Most clients can reference an environment variable instead of storing the key. Export it from your shell profile, ideally from a secret store rather than as a literal. For example, on macOS with the Keychain:
# once: store the key (read -s keeps it off the screen and out of shell history)
read -rs "k?Gcore API key: " && security add-generic-password -U -a "$USER" -s gcore-api-key -w "$k"; unset k
# in ~/.zshrc or ~/.bashrc
export GCORE_API_KEY="$(security find-generic-password -s gcore-api-key -w)"In bash, use read -rsp "Gcore API key: " k instead. -U replaces a key you
stored before. Don't type the key at the prompt of
security add-generic-password -w itself: that prompt keeps only the first 128
characters, and a Gcore API key is longer, so the stored key is cut short and
every call fails with 401.
Clients only see variables that were exported in the environment they were started from, so start the client from a shell that has the variable, or restart it after editing your profile.
Claude Code. Keep the single quotes: the config stores the reference
${GCORE_API_KEY}, which is expanded when the server starts.
claude mcp add gcore -s user -e 'GCORE_API_KEY=${GCORE_API_KEY}' \
-- uvx --from "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git" gcore-mcp-serverCursor (~/.cursor/mcp.json). Cursor expands ${env:NAME}. Alternatively,
"envFile": "/path/to/.env" loads variables from a file.
{
"mcpServers": {
"gcore": {
"command": "uvx",
"args": ["--from", "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git", "gcore-mcp-server"],
"env": {
"GCORE_API_KEY": "${env:GCORE_API_KEY}"
}
}
}
}OpenAI Codex (~/.codex/config.toml). env_vars forwards variables by name,
so the value never enters the file. Start codex from a shell where
GCORE_API_KEY is exported, then check the server with codex mcp list.
[mcp_servers.gcore]
command = "uvx"
args = ["--from", "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git", "gcore-mcp-server"]
env_vars = ["GCORE_API_KEY"]By default, Codex runs reads (call_read_tool) without asking, and asks before
writes and deletes. codex exec can't ask, so it blocks changes. To allow them in
headless runs, add the following:
[mcp_servers.gcore.tools.call_write_tool]
approval_mode = "approve"
[mcp_servers.gcore.tools.call_destructive_tool]
approval_mode = "approve"
[mcp_servers.gcore.env]
GCORE_CONFIRM_VIA = "model"The last setting is needed because Codex declines the server's own approval prompt when no one can answer it.
opencode (~/.config/opencode/opencode.json, or opencode.json in a project).
{file:path} reads the key from a private file, and {env:NAME} reads an
environment variable instead (an unset variable becomes an empty key). To create
the file without the key appearing in shell history:
read -rs "k?Gcore API key: " && (umask 077; printf %s "$k" > ~/.config/opencode/gcore-api-key) && unset kIn bash, use read -rsp "Gcore API key: " k instead.
{
"$schema": "https://opencode.ai/config.json",
"mcp": {
"gcore": {
"type": "local",
"command": ["uvx", "--from", "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git", "gcore-mcp-server"],
"environment": {
"GCORE_API_KEY": "{file:~/.config/opencode/gcore-api-key}"
}
}
}
}Check it with opencode mcp list, which should show gcore as connected. opencode
loads every MCP tool into context up front, which is why the default dynamic mode
(6 tools) suits it. Avoid GCORE_TOOLS=* here. opencode can't show approval
prompts, so destructive calls use the confirmation-token round trip described
under "How approval works".
Claude Desktop (claude_desktop_config.json). Claude Desktop doesn't expand
variables, and as a GUI app it doesn't see your shell profile. Either put the key
in the env block, using the same JSON as Cursor, and keep the file private
(chmod 600), or, on macOS, read the key from the Keychain at launch:
{
"mcpServers": {
"gcore": {
"command": "/bin/sh",
"args": ["-c", "GCORE_API_KEY=\"$(security find-generic-password -s gcore-api-key -w)\" exec \"$HOME/.local/bin/uvx\" --from gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git gcore-mcp-server"]
}
}
}Use the full path to uvx (which uvx), because GUI apps get a minimal PATH.
The API key is the only setting you need. Then ask, for example, "Which of my volumes are not attached to anything?" or "Create an SSH key called deploy and show me the public key."
Cloud projects and regions. You don't configure them; work across as many as you like and name them in plain words ("in my staging project", "in Frankfurt"). When a request doesn't say:
Project: the account's default project is used, and the answer says which one, so the model can switch when you meant another. Deletes and other destructive operations never assume a project.
Region: listing ("what volumes do I have?") searches every region at once, and each item shows its region. Other operations act on a specific resource, so they take the region from it, or the model asks you.
To keep the server to one project and/or region, set GCORE_CLOUD_PROJECT_ID
and/or GCORE_CLOUD_REGION_ID. If you deny cloud.projects.list or
cloud.regions.list with GCORE_DENY_TOOLS, nothing is looked up for you: pin
that value, or every call must name it.
Related MCP server: MCP Cloud Services Server
How it works: modes
GCORE_MCP_MODE selects what the client sees. Tool-definition sizes were measured
with Claude's tokenizer (count_tokens), and o200k numbers are in brackets; these
budgets are enforced by tests/test_protocol.py.
mode | tools | tool-definition tokens | when to use |
| 6 | 1,719 (1,203) | Almost always. Reaches all ~820 operations. |
| 5 | 1,374 (937) | If you don't want sandboxed code. |
| one per operation matched by | about 800 per tool | Classic one-tool-per-operation, for a known small set of operations. |
| 823 | — (442,232) | Only for clients that defer tool loading (for example Claude Code Tool Search). |
Dynamic mode has these tools:
tool | what it does |
| Finds operations from plain words ("delete dns record") or a resource path ( |
| Returns the exact argument schema and docs of one operation, and which call tool runs it. |
| Runs one read operation. Marked read-only, so clients can run it without asking. |
| Runs one operation that creates or changes something. |
| Runs one operation that deletes, overwrites or interrupts something. |
| Runs a short Python script that reads through many operations, for loops, joins and filtering. Intermediate data never enters the conversation. |
Arguments are validated against the operation's schema before anything is sent.
Calls are split by risk so that your client's own approval settings work: reads
can run without prompts, while writes and destructive calls are confirmed. Each
call tool refuses operations of another class. In read-only mode only
call_read_tool is offered.
execute_code sandbox. Scripts call operations as typed Python functions. An
operation's module is its name without the method, so cloud.volumes.list is
list in gcore.cloud.volumes:
import asyncio
import gcore.cloud.volumes as volumes
import gcore.cloud.instances as instances
vols, insts = await asyncio.gather(volumes.list(), instances.list())
[v['name'] for v in vols['results'] if not v.get('attachments')]The modules are generated from the SDK: arguments match the operation's schema, and
results are plain dicts with the SDK's field names (get_tool_schema lists them).
Scripts are type-checked before they run. A definite mistake stops the script
before any API call, with the fix: a misspelled operation, argument or result field
(Unknown key "floating_ip_adress" … did you mean "floating_ip_address"?), a wrong
value for a fixed choice, an undefined name. The checker's other findings, such as
"this value may be None", don't stop the script; they are shown only if it then
fails. call_tool(name, **kwargs) also works, for operation names held in
variables, but its results aren't checked.
Scripts run in Pydantic Monty, a Python
interpreter in a separate worker process. They can use json, re, datetime and
asyncio (asyncio.gather runs calls in parallel). They have no access to files,
the network, environment variables or other imports, and cannot use classes or
with. Each script gets 20 s of CPU, 256 MB of memory, 500 API calls and 55 s of
wall time (GCORE_CODE_TIMEOUT), and reports progress after each API call. Most
clients give up on a request after 60 s, so raise the limit only for a client that
waits longer. Every API call from a script goes through the same checks as a direct
call. Scripts are read-only by default: changes go through call_write_tool and
call_destructive_tool, one approved call at a time. Set GCORE_CODE_WRITES=true to
let scripts make changes too; then execute_code is marked destructive, and clients
ask before every script. Calls that GCORE_CONFIRM requires approval for still
can't run inside a script (unless the client asks the user directly): the script
stops, and the model makes that call with call_write_tool or
call_destructive_tool.
Direct mode registers one tool per operation, named after the SDK path
(cloud_instances_list). GCORE_TOOLS selects them with patterns (see "Writing
patterns" below). Project and region lookups are always included. Direct mode needs
GCORE_TOOLS; without it, the server uses dynamic mode.
GCORE_TOOLS="cloud.instances,cloud.networks,dns.zones,cloud.k8s.clusters.*"In dynamic mode, GCORE_TOOLS limits what search can reach.
Writing patterns
GCORE_TOOLS and GCORE_DENY_TOOLS take comma-separated patterns over operation
names. An operation's name is its SDK path, such as cloud.volumes.delete. All
823 are listed in docs/OPERATIONS.md, with their access class.
A name without wildcards matches that operation and everything below it:
dns.zonescoversdns.zones.list,dns.zones.rrsets.deleteand so on.*matches any characters, dots included:cloud.*.deletematchescloud.volumes.deleteandcloud.k8s.clusters.pools.delete.?matches one character, and[...]matches a set.Matching is case-sensitive.
Many operations have a
*_and_pollvariant that sends the same request and then waits for it to finish, such ascloud.volumes.delete_and_poll. Denying an operation also denies its*_and_pollvariant. When selecting tools, end the pattern with*to get both.
Check a pattern before using it. This needs no API key:
gcore-mcp-server --list 'cloud.*.delete*'If GCORE_TOOLS as a whole matches nothing, the server refuses to start rather
than expose more than you meant. A single pattern that matches nothing (in
GCORE_TOOLS or GCORE_DENY_TOOLS) is logged as a warning at startup; it is
usually a typo.
goal | setting |
Block every delete |
|
No IAM access, no project changes |
|
Only DNS in dynamic mode |
|
Instances and volumes as plain tools |
|
Upgrading from an older version? Named toolsets (
management,instances, …) are gone. If yourGCORE_TOOLSmatches no operation, the server logs an error and exits (code 2) instead of opening the whole API. Replace toolset names with SDK paths, or removeGCORE_TOOLS.
Safety
Every call goes through the same checks: direct tools, the call tools, and calls
made from inside execute_code.
setting | effect |
| Only read operations run. In direct mode, write tools are not even listed. |
| Deletes and other destructive operations need the user's approval. |
| Every change needs approval. |
| No approval prompts, for trusted automation. Read-only mode and the deny-list still apply. |
| Blocks these operations completely: no schema, no call, not in scripts or direct mode. Search lists them marked |
Access classes. Every operation is classified as read, write or destructive
from its name. For example, delete, replace, resize, rebuild,
action (start/stop/reboot), toggle and regenerate are destructive. A CDN cache
purge is a write: it drops cached copies only, and deploys need it. The class is shown in search results and
schemas, and the full list is in docs/OPERATIONS.md.
How approval works:
The client prompts the user. If the client can show the server's questions to you (the MCP feature for this is called elicitation), the client asks you directly and the call runs only if you approve. Newer clients get an input request they answer and retry; older ones get a classic elicitation.
Fallback for other clients. The call is refused with CONFIRMATION REQUIRED and a token. The model must ask you, then repeat the call with that token. The token is bound to the exact operation and arguments, so it can't approve a different call, and it works once, within 10 minutes.
Batches. call_write_tool and call_destructive_tool take a list of argument
objects to run the same operation once per item (up to 20), for example deleting
several volumes. The user sees every item in one prompt and approves once (or one
token covers exactly that list); then the items run in parallel and each reports
its own result or error.
File uploads. fastedge.binaries.create takes the path of a local .wasm
file, not its contents: the server reads the file and uploads it, so an 11 MB app
doesn't have to pass through the conversation. The server must run on the
machine that has the file (stdio does). Only a file that starts with the
WebAssembly signature, up to 100 MB, is accepted, so a path can't be used to
upload a key or any other file.
Set GCORE_CONFIRM_VIA=model to always use the fallback, for example when a
client advertises the feature but doesn't show the prompt well.
Headless runs (claude -p, CI agents) have no one to answer a prompt, so
clients cancel it and the call is refused. The refusal says so and names these
settings: GCORE_CONFIRM_VIA=model lets the agent approve through the token
round trip, and GCORE_CONFIRM=none suits fully trusted automation.
The fallback relies on the model following instructions. Your client's own approval prompt for destructive tools is the human checkpoint.
What read-only mode does and doesn't guarantee. Read-only mode, the deny-list
and approval apply to every call made through this server. They don't limit the
API key itself. If your client runs an agent that has shell access (Claude Code,
Cursor), it can read the key from the client's config file and call the Gcore API
directly. For a hard guarantee, give the server a key that can't do more than you
allow: an API token for a user with a read-only role. Read operations can also
return secrets, such as kubeconfigs, a Kubernetes cluster's CA key
(get_certificate, enough to mint admin credentials), secrets and access keys. Hide those with
GCORE_DENY_TOOLS if their contents shouldn't reach the model, for example:
GCORE_DENY_TOOLS='cloud.k8s.clusters.kubeconfig.*,cloud.k8s.clusters.get_certificate,*.secrets.*,*credentials*,*.access_keys.*,iam.api_tokens.*'Read operations are recognised by their method names. A test
(test_read_operations_only_send_get) checks each one against the HTTP method the
SDK sends, so an SDK upgrade can't slip a write into read-only mode unnoticed.
Credentials. The server never passes the API key to the sandbox or to the model (but see above for agents with shell access). Some responses do contain secrets: for example, when the platform generates an SSH key pair, the response includes the private key.
HTTP transport. With GCORE_TRANSPORT=http the server is read-only by
default; set GCORE_READ_ONLY=false to allow changes. The Host and Origin headers of
every request are validated against GCORE_ALLOWED_HOSTS and
GCORE_ALLOWED_ORIGINS, which protects against DNS rebinding. Loopback names, the
bound address and same-origin requests are always accepted. Clients are not
authenticated: anyone who can reach the listener can use the server's API key. The
server listens on 127.0.0.1 only; don't expose it through a port forward or proxy.
The SSE transport, deprecated by the MCP specification, is refused.
These rules apply only when the server is started with gcore-mcp-server.
Configuration reference
Only GCORE_API_KEY is required. .env.sample lists every setting
with its default and when to change it. Booleans take 1/true/yes/on or
0/false/no/off; any other value stops the server, so a typo can't silently turn
a safe default off.
variable | default | meaning, and when to change it |
| (required) | Gcore API key. Without it, tools are listed but every call fails with a clear error. For a hard read-only guarantee, use a token of a read-only user (see Safety). |
| unset | Pin cloud calls to one project and/or region. Unset: the account's default project, and list calls search every region. Pin them when an agent should only touch one project or region. |
|
| API endpoint. Change only for a non-production endpoint. |
|
| Seconds a |
|
| The SDK's own limit for one task poll. Rarely needed: |
|
|
|
| unset (everything) | Glob patterns over SDK paths: the direct tools in direct mode; limits search and calls in dynamic mode. Every operation is listed in docs/OPERATIONS.md; check a pattern with |
|
| Offer |
|
| Let |
|
| Seconds an |
|
| Allow only read operations. Use for exploration and audits. |
|
| What needs approval: |
| unset | Patterns of operations to block (listed in search as blocked) (see "Writing patterns" and docs/OPERATIONS.md), e.g. ones that return secrets. |
|
| How approval is asked: |
|
| Larger results (the JSON the model receives, per tool result or script return value) are trimmed, with a note saying how many items are left out. 40000 is about 16k tokens: ~30 instances or volumes, ~4 security groups. Lower it to save context; |
|
|
|
|
| HTTP port. The server always listens on |
| empty | Extra allowed |
The SDK's own GCORE_CUSTOM_HEADERS is ignored (with a warning): the server
sends no custom headers to the API.
Settings for live tests, scenarios and evals (GCORE_LIVE_*,
ANTHROPIC_API_KEY) are described in CONTRIBUTING.md.
Installing
To run without installing:
uvx --from "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git" gcore-mcp-serverTo install it as a tool:
uv tool install "gcore-mcp-server@git+https://github.com/G-Core/gcore-mcp-server.git"These commands follow the main branch. To pin a release, add its tag to the URL,
for example …/gcore-mcp-server.git@v1.3.0. Releases are listed on the
releases page.
Upgrading
See CHANGELOG.md for what changed in each version, and breaking
changes to check before upgrading. With uvx, you get the newest version the next
time your client starts the server, because uvx fetches the branch or tag on every
start. With uv tool install, run uv tool upgrade gcore-mcp-server.
If you pinned a tag, change it to the new one.
Contributing
Development setup, tests, SDK upgrades and releases are covered in CONTRIBUTING.md.
License
Available Tools
6 toolscall_destructive_toolCall Destructive ToolADestructive
Run a destructive operation (deletes, overwrites or interrupts something). Asks the user to confirm.
Inputs: name (required), arguments, confirm_token.
call_read_toolCall Read ToolBRead-only
Run a read operation (no side effects) by name.
Inputs: name (required), arguments.
call_write_toolCall Write ToolB
Run a write operation (creates or changes something). May ask the user to confirm.
Inputs: name (required), arguments, confirm_token.
execute_codeExecute CodeARead-only
Run a short Python script against the Gcore API for tasks needing several calls, loops or filtering; intermediate data stays out of the conversation. Call operations as typed functions: an operation's module is its name without the method, e.g. import gcore.cloud.volumes as volumes then await volumes.list(region_id=76). Results are dicts with the fields get_tool_schema's 'returns' lists (list items under its list_key, usually 'results'). Scripts are type-checked first: a wrong operation, argument or field name stops the script before any call, with the fix. Also available (await each): call_tool(name, **kwargs) for names in variables, search_tools(query), get_tool_schema(name). Import json, re, datetime, asyncio before use (asyncio.gather runs calls in parallel; neither it nor json.dumps takes default=/return_exceptions=). No classes, with, files, network or env. Returns the last expression and print() output. A script stops after 55 s: split large sweeps (e.g. one project per script). Scripts can only call read operations; make changes with call_write_tool or call_destructive_tool.
Inputs: code (required).
get_tool_schemaGet Tool SchemaARead-only
Get one Gcore API operation's description, argument JSON schema and result field names ('returns'; a{b,c} is a nested object, x[] a list), by name.
Inputs: name (required).
search_toolsSearch ToolsARead-only
Find Gcore API operations. Query in plain words ('list instances', 'delete dns record') or by resource path ('cloud.volumes') to list its operations. Returns names, summaries and (if not read) access. Next: get_tool_schema.
Inputs: query (required), limit, access.
Tool Schema Changelog
Recent tool additions, removals, and schema changes observed during successful MCP inspections.
Loading tool schema changelog…
TDQS
Scored across 6 tools
The discovery pair (search_tools vs get_tool_schema) is clearly separated by purpose, and the call_read/call_write/call_destructive triple is cleanly partitioned by side-effect class as flagged in search results. The only soft overlap is call_read_tool vs execute_code for a single read operation, but the descriptions steer simple reads to the former and multi-call/filtering work to the latter.
All names are snake_case verb_noun (search_tools, get_tool_schema, call_read_tool, call_write_tool, call_destructive_tool, execute_code). The call_* prefix forms a predictable family for the three execution tiers, which makes the pattern easy to extrapolate.
Six meta-tools is the right shape for a gateway over a large cloud API surface — it avoids exposing hundreds of per-operation tools while still covering discovery, schema inspection, execution tiers, and scripting. Each tool earns its place with no filler.
The surface covers the full lifecycle: discover a name, learn its schema/returns, then read, write, or destroy it, plus a scripting escape hatch for multi-call workflows. The notable gap is that execute_code is read-only, so bulk or batched writes and deletes must go one call at a time, and there is no tool for managing auth/context or paginating large results explicitly.
Maintenance
Related MCP Connectors
Provides capabilities that let LLM agents perform a range of infrastructure management tasks.
Unified API to query AWS, GCP, Azure and generate Terraform/CLI execution kits for AI agents.
Manage American Cloud VMs, Kubernetes, databases, storage, networks and DNS from your AI assistant.
Manage HepCloud (Turkish cloud) servers and managed PostgreSQL from your AI assistant. OAuth 2.1.
Related MCP Servers
- AlicenseCqualityDmaintenanceEnables AI assistants to interact with Google Cloud Platform resources through natural language queries. Supports querying and managing GCP services like Compute Engine, Cloud Storage, BigQuery, and more across multiple projects and regions.91,244 npmMIT
- AlicenseCqualityDmaintenanceEnables AI assistants to manage multi-cloud resources (AWS, Azure, GCP) including resource operations, cost analysis, monitoring metrics, and security compliance checks through natural language commands.2613 npm2MIT
- AlicenseCqualityDmaintenanceProvides tools and context for interacting with Google Cloud services, enabling natural language management of billing, monitoring, logging, IAM, Spanner, and more.56186 npmApache 2.0
- FlicenseNot gradedqualityDmaintenanceProvides 30+ read-only tools for querying Google Cloud Platform infrastructure, designed for AI assistants and Terraform workflows.-