Get started

Concepts

The mental model behind Spacefix: projects, agents, replicas, keys, how a call travels, what runs where, and what we store.

This page gives you the model that the rest of the documentation assumes. Read it once after the Quickstart, and come back when a word is unclear.

The model in one picture

  • An account owns projects.
  • A project is one MCP endpoint, https://api.spacefix.io/mcp/<project id>, with its own keys, settings, connected agents and tools.
  • Your service runs an SDK. Each running copy is an agent: it holds one outbound connection to the project, authenticated with an agent key.
  • An MCP client calls the project's endpoint with a client key.
  • The gateway sends each call to one connected, enabled agent and returns the answer.

The running agent is the source of truth for what a project offers. The gateway does not hold your tools; the dashboard shows what the connected agent registered right now.

Terms

TermMeaning
ProjectOne MCP endpoint. Has a project id (a UUID, the last segment of the endpoint URL), a name, keys, settings and, while one is connected, agents. The project id is not secret and the endpoint alone grants nothing: every request needs a key.
AgentOne running process holding one open connection to a project. A project with three copies of your service has three agents. An agent exists only while connected; its agent id (ten hex characters, such as 47377b2f4e) is made when it connects and is gone when it disconnects.
ReplicaOne of several copies of your service, each running the SDK, so each its own agent of the same project. See Running replicas.
ToolA function a client calls with arguments, such as get_order. Registered with a name, a description and a JSON Schema for its arguments.
ResourceData a client reads by URI, such as orders://open, with no arguments.
PromptA message template a client lists in its menu and fills in. Its arguments are always strings.
CallOne request to run a tool, read a resource or render a prompt (tools/call, resources/read, prompts/get). Listing (tools/list and so on) is not a call.
KeyA secret that authenticates an agent or a client to one project. It looks like sf_live_ followed by 22 characters. It is shown once and stored only as a hash.
AllowanceThe number of billable calls your plan includes each UTC month. See Plans and limits.
ClientAnything that calls the endpoint: Claude Code, Claude Desktop, Cursor, VS Code, the MCP Inspector, or your own code.

Key kinds

Every key has a kind, a label, an optional expiry and, for kinds that can call tools, an optional tool allow-list and an access level: read and write (the default), or read only, which limits the key to tools that read.

KindDashboard labelConnects an agent (SDK)Calls tools (MCP client)Allow-list
agentAgentYesNoNot applicable
clientClientNoYesYes
fullFullYesYesYes

A genuine key used on the wrong door is refused with 403:

  • An agent key on the MCP endpoint: This is an agent key. MCP clients connect with a client key.
  • A client key where an agent connects: This is a client key. Agents connect with an agent key.

A tool reads when your agent sets readOnlyHint: true on it, or when you mark it Read in the dashboard. Any other tool counts as a write. A project's Client access setting can limit every client to reads. See Read-only keys.

Every new project starts with one full key labelled Default. For real use, create one agent key for each deployment and one client key for each client or person. Details are in Projects and keys.

What runs where

Runs in your infrastructureRuns on the gateway
Your service, the SDK and every handler you writeThe MCP endpoint your clients call
Your database, secrets and network accessKey checks, plan and rate checks, and validation of arguments against your schema
The decision of what a tool doesRouting a call to one of your agents, timeouts, the optional result cache
The one outbound HTTPS connection per replicaThe dashboard: agents, logs, traces, usage, keys, alerts

No code of yours runs on the gateway, and no inbound port is opened on your side. The agent dials out; the gateway pushes calls down that connection, and the agent returns each result with an ordinary HTTPS request.

The life of a call

  1. Your service starts. The SDK connects out to the gateway with an agent key and announces its tools, resources and prompts. The connection stays open, and the SDK reconnects by itself if it drops.
  2. A client calls your project's endpoint with a client key, for example tools/call with get_order and {"id":"1"}.
  3. The gateway checks, in order: the key (valid, right kind, not expired or revoked), whether the project is suspended, the client address allow-list if you set one, the project's request rate, the monthly allowance, and whether any agent is connected.
  4. The gateway validates the arguments against the JSON Schema your tool registered. A call that does not match never reaches your code.
  5. The gateway picks one agent that has the tool, in turn across your enabled agents, and sends the call down its connection.
  6. Your handler runs in your process and returns a value (or throws).
  7. The result goes back: the SDK posts it, the gateway returns it to the client as the tool's result, and records the call: tool, time, duration, outcome and sizes.

If a tool takes longer than the project's call timeout (30 seconds by default, never more), the client gets an error result and your handler's late result is discarded.

At-most-once delivery

The gateway sends a call to one agent and does not retry it. If that agent dies while running the call, the call fails with Agent disconnected before returning a result.; the gateway does not send it to another replica, because it cannot know whether your handler already did its work. The same goes for a call that times out: your handler may still have run.

Design for it. A tool that writes should accept a caller-supplied request id and ignore a repeat (see Idempotency), so a model or client that retries after a failure does not do the work twice. The SDK does retry posting a result back to the gateway after a network failure; that is separate from running the call again.

Timeouts

  • The default wait for a tool, a resource read or a prompt is 30 seconds.
  • In Project settings you can set Call timeout (seconds) to any whole number from 1 up to 30. You can lower it, not raise it.
  • When it expires the client gets a result with isError and Request for tool "<name>" timed out after <ms>ms., and the call is logged as Timed out. It counts as a billable call because it reached your agent.

For work that takes longer, return a job reference and add a second tool to poll it.

Why state must be shared

When you run more than one copy of your service, calls are spread across them and each copy has its own memory. A tool that keeps data in a variable gives different answers depending on which copy received the call.

This is a real result from the SDK's example agent, run as two replicas (A and B) of one project and called through the gateway:

add_item   {"item":"x"}  ->  added x on A
get_all_items            ->  {"replica":"B","items":[]}        <- served by B, which never saw the write
get_all_items            ->  {"replica":"A","items":["x"]}     <- served by A

The write landed on A, the next read was served by B, and the list looked empty. The tool did nothing wrong; the data was not shared. Keep state where every replica can see it: a database, a cache or a queue, and treat handlers as stateless. There is no affinity: do not rely on the same agent answering next time. See Running replicas for a worked example and the fix.

What we store

The gateway keeps what it needs to route, bill and show you what happened, and nothing of the content of your calls.

We storeWe do not store
The names, descriptions and schemas of your tools, resources and prompts, only while an agent that registered them is connectedYour code, your data or your secrets
A hash of each API key, with its prefix, label, kind, expiry and last-used timeThe secret of a key, after it is shown once
Call metadata: tool name, kind (tool, resource or prompt), time, duration, outcome, the size in bytes of the arguments and the result, the label of the key used, the MCP client's name and version as it reported them and the caller's User-Agent, the runtime your agent runs on, a request id and a trace idThe values of the arguments or the result
The names of the arguments passed (up to 20 names per call)Argument values
For a failed call, the error message, shortened to 300 characters
Your settings: tool controls, project settings, webhooks, account details

Arguments and results travel through the gateway in memory on their way to and from your agent. The only time a result is held longer is the opt-in result cache, in the gateway's memory for the number of seconds you set.

Four switches that stop traffic

WhatWhere you set itEffectSurvives an agent restart?
Disabled agentAgents page, DisableThe agent stays connected but is sent no new calls, and its tools are left out of the lists clients see. Calls already running on it finish.No: a reconnecting agent is a new connection and starts enabled
Disabled toolProject page, tool EditThe tool disappears from tools/list for every client and cannot be called. Your agent is unaffected.Yes
Revoked keyProject page, RevokeThe key stops working on the next request, and an agent connected with it is disconnected.Yes (permanent)
Suspended project or accountThe service operatorAgents and clients are refused with the reason shown.Until reinstated

Next steps