xmagic-sdk
Python SDK and CLI for xMagic, Stochastic's AI agent platform.
Status: alpha scaffold. Parts of the surface below are still stubs that raise
NotImplementedError— each is marked with the roadmap phase that implements it. See DESIGN.md for the design plan, TODO.md for current work, and CHANGELOG.md for what shipped.
What it does
Working today:
- MCP servers — scaffold containerized (Dockerfile included) MCP servers you can register as xMagic custom tools.
- xMagic API — chat (sync + streaming), file uploads, Drive (knowledge base), skills packaging, with a matching async client. Request/response shapes are verified against the live API and locked with recorded-fixture tests.
- Bring your own model —
provider:modelrefs backed by your own key.xmagic:<agent_id>andopenai:<model>work today, over oneProviderinterface.
Planned:
- More providers (Phase 3) —
litellm:for the ~150 vendors LiteLLM reaches, including Anthropic and Google. Their native adapters (anthropic:,google:) are reserved but unimplemented. - Local web app (Phase 5) —
xmagic serveruns the xMagic web app locally via proxy.
Install
Requires Python 3.11–3.14.
uv pip install xmagic-sdk # core
uv pip install "xmagic-sdk[all]" # + all provider/serve/mcp extras
Extras are granular if you don't want everything — [mcp] for the server
scaffold, [serve] for the local web app, [openai] for the OpenAI provider,
and [litellm] for the long tail. There is no [anthropic] or [google]:
those adapters aren't implemented, and LiteLLM already reaches both. pip works
too if you don't use uv.
You install
xmagic-sdkbut importxmagic. The two names differ becausexmagicon PyPI belongs to an unrelated project registered in 2022, so it was never available to us.If you used this package before 0.1.0, note that releases 0.0.1–0.0.3 installed a
xmagic_sdkmodule with a completely different API. Upgrading removes it, soimport xmagic_sdkwill now raise an error explaining the change. Pinxmagic-sdk==0.0.3if you still depend on that API — see CHANGELOG.md for what moved.
From a checkout:
uv pip install -e . # core
uv pip install -e ".[all]" # + all provider/serve/mcp extras
Verify it landed:
xmagic version
Getting started
1. Get an API key
In xmagic.ai: profile → API keys. You'll also want an agent id — create an agent in Studio, and its id appears in the agent's URL.
2. Configure
xmagic configure # prompts for the key, hidden input
This writes ~/.config/xmagic/config.toml with mode 600. Pass
--agent <agent_id> to set a default agent, or --api-key to skip the prompt
in a script.
Prefer environment variables? XMAGIC_API_KEY and XMAGIC_BASE_URL both work
and take precedence over the file:
export XMAGIC_API_KEY="xm-..."
Full precedence is explicit arguments → environment → config file →
defaults, so you can keep a config file for everyday use and override it
per-command. XMAGIC_CONFIG_PATH relocates the file itself.
The config file looks like this, and you can edit it directly:
[xmagic]
api_key = "xm-..."
base_url = "https://api.xmagic.ai/xmagic-backend/v1"
default_agent_id = "..."
[providers.openai] # used by `-m openai:<model>`
api_key = "sk-..."
Provider keys are also read from the usual OPENAI_API_KEY,
ANTHROPIC_API_KEY, and GOOGLE_API_KEY variables. Keys are only ever
written to your user config directory, never into a project folder.
3. Talk to your agent
xmagic chat --agent <agent_id> "Summarize our Q3 goals" # one-shot
xmagic chat --agent <agent_id> # interactive session
Responses stream by default; --no-stream waits for the full reply instead.
If you set default_agent_id during configure, drop the --agent flag.
When the agent thinks out loud, its reasoning is printed dimmed, above the
answer.
Attach files with -f (repeatable), and pick the chat's UI context with
--chat-type:
xmagic chat --agent <agent_id> -f notes.md -f data.csv "What changed?"
xmagic chat --agent <agent_id> --chat-type playground "Try something"
An interactive session reuses a single chat, so the agent keeps its context across turns.
4. Use it from Python
from xmagic import XMagicClient
client = XMagicClient() # reads env/config; or XMagicClient(api_key="xm-...")
chat = client.chats.create("<agent_id>", title="demo")
# Streaming
for event in client.chats.stream("<agent_id>", chat.id, "Explain xMagic skills"):
if event.type == "response":
print(event.text, end="")
# Blocking
resp = client.chats.query("<agent_id>", chat.id, "One-sentence summary?")
XMagicClient is a context manager, so with XMagicClient() as client: closes
the underlying HTTP connection for you. It retries 429 and 5xx with
exponential backoff, honoring Retry-After.
AsyncXMagicClient mirrors it 1:1 — same resources, same arguments, same
returns. Await each call, and iterate stream with async for:
from xmagic import AsyncXMagicClient
async with AsyncXMagicClient() as client:
chat = await client.chats.create("<agent_id>", title="demo")
async for event in client.chats.stream("<agent_id>", chat.id, "Explain xMagic skills"):
if event.type == "response":
print(event.text, end="")
5. Build a custom tool (MCP server)
xmagic mcp init my-tool # scaffold: Dockerfile, compose, MCP server
cd my-tool && docker compose up --build
That serves MCP over streamable HTTP at http://localhost:8000/mcp. xMagic
needs a public HTTPS URL to reach it, so for development expose it with a
tunnel:
cloudflared tunnel --url http://localhost:8000
Before going anywhere near a tunnel, exercise it locally — tools list and
tools call speak MCP straight to the server:
xmagic tools list --url http://localhost:8000/mcp --api-key "$TOOL_API_KEY"
xmagic tools call ping --url http://localhost:8000/mcp --api-key "$TOOL_API_KEY" -a message=hi
That skips the whole tunnel → register → open a chat → hope-the-agent-calls-it
loop, which otherwise makes a broken tool and a tool the agent declined to use
look identical. Pass --json for scriptable output; call exits non-zero when
the tool reports an error, so it works in CI. Repeat -a key=value for multiple
arguments, or pass --json-args '{"k": "v"}'.
Then register the resulting public https://.../mcp URL in the dashboard under
Custom tools → Create tool. xmagic tools register --name ... --url ...
prints the full checklist. Set TOOL_API_KEY in your .env to require a
shared secret — the generated server rejects unauthenticated calls with 401.
6. Package a skill
xmagic skills new my-skill # scaffold SKILL.md
xmagic skills validate my-skill # check frontmatter and layout
xmagic skills pack my-skill # -> my-skill.zip, ready to upload
Upload the zip in the dashboard under Skills.
7. Use a non-xMagic model
chat takes a provider:model ref backed by your own key. OpenAI is
implemented:
export OPENAI_API_KEY="sk-..."
xmagic chat -m openai:gpt-5 "Hello!"
Or from Python, through the same Provider interface the xMagic path uses:
from xmagic.providers import ChatMessage, get_provider
provider = get_provider("openai:gpt-5") # reads OPENAI_API_KEY
for chunk in provider.stream([ChatMessage(role="user", content="Hello!")], model="gpt-5"):
print(chunk.text, end="")
Two differences from the xMagic path are worth knowing. model is a real model
name here, not an agent id — OpenAI picks per call, so there's no agent and no
server-side session, and multi-turn context is whatever you pass in messages.
And -f/--file is xMagic-only, since uploads are an xMagic feature.
Errors arrive as this SDK's own types, so you catch XMagicError regardless of
which vendor failed — a 429 from OpenAI raises the same RateLimitError a 429
from xMagic would.
anthropic: and google: are not implemented; use litellm: for those once
that adapter lands (Phase 3).
Next steps
Runnable scripts for each of the flows above live in
examples/ — chat, streaming, files and Drive, and the MCP
scaffold walkthrough (that one needs no API key).
xmagic --help lists every command, and each subcommand takes --help too.
See DESIGN.md for how the pieces fit together.
Troubleshooting
No API key configured — run xmagic configure, or export
XMAGIC_API_KEY. Check what's actually being picked up with
xmagic configure --help and remember env vars override the config file.
A command prints ... lands in Phase N (see DESIGN.md) — that feature is
scaffolded but not implemented yet. See the status note at the top of this
README.
ModuleNotFoundError: No module named 'xmagic' — the import name is
xmagic, but the package to install is xmagic-sdk. See the note under
Install.
ImportError mentioning xmagic_sdk — you upgraded from 0.0.x, where the
module was called xmagic_sdk. It is xmagic from 0.1.0 on, with a different
API; the error text names what changed.
401 from your MCP server — the generated server requires TOOL_API_KEY
when set. Send it as either x-api-key or Authorization: Bearer <key>.
xMagic can't reach your MCP server — it must be public HTTPS. localhost
won't work; use a tunnel for development.
Development
uv sync --all-extras
uv run pytest
uv run ruff check .
uv run ruff format --check .
CI runs all four across Python 3.11–3.14, and gates on formatting as well as
linting — run uv run ruff format . before pushing.
Commit messages follow Conventional Commits
(feat:, fix:, docs:, test:, chore:, ...; optional scope, e.g. feat(mcp): ...).
Contributing
Contributions are welcome — see CONTRIBUTING.md for setup and the PR workflow, and ISSUES.md for filing bugs, feature requests, and security reports. All participants are expected to follow our Code of Conduct.
License
Apache-2.0 © Stochastic
Metadata
Release files for xmagic-sdk 0.2.0
For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.
Source distribution (sdist)
| File | Size | Uploaded | Provenance | Actions |
|---|---|---|---|---|
| xmagic_sdk-0.2.0.tar.gz | 91.1 kB | With provenance | Details for xmagic_sdk-0.2.0.tar.gz |
Built distribution (wheel)
| File | Interpreter | ABI | Platform | Actions Reset |
|---|---|---|---|---|
| xmagic_sdk-0.2.0-py3-none-any.whl | Python 3 | none | any | Details for xmagic_sdk-0.2.0-py3-none-any.whl |
Total release size: 145.6 kB
Release files / xmagic_sdk-0.2.0.tar.gz
| Download URL | xmagic_sdk-0.2.0.tar.gz |
|---|---|
| Size | 91.1 kB |
| Tags | Source |
|
SHA-256 checksum How to use checksums |
9d3d5849cc619aaf9cd6eb1e2d7fe79d89107befb8f1735f549527325838835e
|
|
BLAKE2b-256 checksum How to use checksums |
64ebaa483b3b95022a856e2971bb2daddfaa87d5400da2b5fe172d72516d8d3a
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logRelease files / xmagic_sdk-0.2.0-py3-none-any.whl
| Download URL | xmagic_sdk-0.2.0-py3-none-any.whl |
|---|---|
| Size | 54.5 kB |
| Tags | Python 3 |
|
SHA-256 checksum How to use checksums |
b7bddfd3a362fcd33e16499e825f7ea3a82338f2c916599a88aa86300c9f0484
|
|
BLAKE2b-256 checksum How to use checksums |
bb22c3379ad06025194233b59c44de7051c7028e9e7ee9b0f755fb7c83be8f53
|
| Upload date | |
|
Uploaded using Trusted Publishing? What is trusted publishing? |
Yes |
| Uploaded via |
twine/7.0.0 CPython/3.13.14
|
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logSecurity for xmagic-sdk 0.2.0
Provenance
Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.
Full provenance
All 2 files in this release have been uploaded with provenance metadata.
Attestation for xmagic_sdk-0.2.0.tar.gz
PyPI Publish Attestation
PyPI verified that this artifact, at this checksum, originated from the publisher listed below.
Signed by GitHub Actions, verified by PyPI on Aug 14, 2026.
Transparency logA note on package security
PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.
To learn more about protecting yourself from malicious actors, visit our package security documentation.