Run and use the PowerContext Server
The ready-to-run Server owns one BuiltinRuntime and exposes it through HTTP. The same process can project a
curated subset of Memory operations as MCP tools. ServerSettings.mcp.enabled controls that projection, so MCP does
not require a separate entry point or extra.
Install and start
Install the Server role together with the CLI to run this instance from the command line:
uv add "powercontext[cli,server]"Start the Server:
uv run powercontext server runThe default listener is 127.0.0.1:8000. SQLite data is stored in powercontext.db. Command options can override the
listener, but binding to a routable address is refused for an unauthenticated Server: enable bearer authentication
(recommended -- terminate TLS at a reverse proxy), or opt in explicitly when TLS is terminated upstream or the network
is otherwise controlled.
# Recommended: authenticate the Server, then bind a routable address (put TLS in front in production).
POWERCONTEXT_SERVER_ACCESS_MODE=enforced \
POWERCONTEXT_SERVER_AUTH_TOKEN="replace-with-a-strong-token" \
uv run powercontext server run --host 0.0.0.0 --port 8080# Or, with TLS terminated upstream / a controlled network, opt in to an unauthenticated bind.
POWERCONTEXT_SERVER_ALLOW_UNAUTHENTICATED_NON_LOOPBACK=true \
uv run powercontext server run --host 0.0.0.0 --port 8080Running --host 0.0.0.0 without one of the above exits with an error rather than silently exposing an
unauthenticated Server.
The process opens its configured database, creates a scope-bound Builtin runtime, and closes owned database, inference, and scheduler resources during shutdown.
Server configuration
ServerSettings keeps transport and Builtin configuration at one level:
| Group | Purpose |
|---|---|
http | Listener host and port |
mcp | Whether MCP is mounted and at which path |
runtime | Source-window and scheduler policy |
database | SQLite or OceanBase configuration |
inference | Optional generation and embedding configuration |
Environment variables use the POWERCONTEXT_SERVER_ prefix. Nested fields are joined with underscores:
export POWERCONTEXT_SERVER_HTTP_PORT="8080"
export POWERCONTEXT_SERVER_DATABASE_URL="sqlite+aiosqlite:///data/powercontext.db"
export POWERCONTEXT_SERVER_RUNTIME_SOURCE_WINDOW_LIMIT="200"
export POWERCONTEXT_SERVER_MCP_ENABLED="false"SQLite is the default database. Select OceanBase by changing only the discriminator and URL:
export POWERCONTEXT_SERVER_DATABASE_KIND="oceanbase"
export POWERCONTEXT_SERVER_DATABASE_URL="mysql+aoceanbase://user:password@host:2881/powercontext?charset=utf8mb4"Both database choices expose full-text search through the same Server API. With an embedding model, SQLite uses sqlite-vec
and OceanBase uses HNSW for vector and hybrid searches.
Inference configuration is documented in Configure Pydantic AI inference.
Set POWERCONTEXT_SERVER_RUNTIME_SCHEDULE_SECONDS to process pending Source windows on a persisted interval. Scheduled
jobs use the SQLite sidecar at POWERCONTEXT_HOME/scheduler.db. Scheduling works with either application database and
requires a configured generation pipeline.
HTTP surface
The source contract is openapi/powercontext.yaml. Generated Pydantic models and operation descriptors under
powercontext.http._generated are build artifacts of that contract.
| Area | Operations |
|---|---|
| Health | liveness and readiness |
| Server discovery | stable deployment identity and protocol contracts |
| Capabilities | source types, Artifact families, extraction, search modes |
| Sources | capture durable content evidence |
| Memory | flush pending Sources, remember explicit entries, search |
| Memory entries | list, get, revise, retire |
| History | list Memory changes |
Every domain request includes a scope ID. That ID selects the Source journal, Memory head, and Trigger cursor used by the Builtin runtime. HTTP request models are transport values and remain separate from Core domain models.
Server errors use the OpenAPI error schema and include a Server-owned X-PowerContext-Request-ID response header
derived from the inbound request span. Validation errors, revision conflicts, missing entries, unavailable inference,
and internal failures map to stable HTTP status codes.
Server identity and compatibility discovery
GET /v1/server-info is protected by server.observe and returns the stable deployment server_id, installed package
version, API contract version, response schema version, and initial feature contracts. It deliberately does not report
health, enabled runtime capabilities, limits, inventory, secrets, filesystem paths, or the authenticated principal.
Use the dedicated health, capabilities, statistics, and access endpoints for those concerns.
All discovery versions use integers with major >= 1 and minor >= 0. A major increment may remove or incompatibly
change the governed contract; a minor increment is backward compatible. The response schema_version governs its fields and
semantics, while api_contract_version is the major/minor projection of the OpenAPI info.version. Each feature
contract version applies only to its listed OpenAPI operation IDs: adding an operation or compatible semantics increments
minor; removing, renaming, or incompatibly changing a listed operation increments major. Compatible clients must ignore
unknown optional fields introduced by a schema minor version.
OpenAPI's root x-powercontext-feature-contracts declares the explicit feature versions. Each governed operation lists
its membership in the same extension; make api-generate produces the discovery metadata from those declarations.
Generation rejects invalid versions (including values outside these bounds), unknown or duplicate memberships, and
features without operations. Version bumps remain an explicit contract edit, not an automatic consequence of changing membership.
The Server stores one identity singleton using the Runtime-owned primary relational database. Startup creates the identity
table idempotently, then atomically creates or loads the singleton, so concurrent initializers converge on one ID and
restarts, package upgrades, backup restore, and replicas sharing that database retain it. If identity schema
initialization or loading fails, Server startup fails before readiness instead of publishing a temporary identity.
The identity repository retries only SQLite busy/locked errors, replaying the complete schema or singleton operation
after rollback. It admits retries for up to five seconds with 50 ms waits; each SQL attempt also retains the driver's
configured busy timeout. Exhaustion and all other errors propagate; offline rotation is not retried.
An in-memory or temporary SQLite deployment receives a new ID with each database lifetime because it has no durable store. Applications using the same shared-memory SQLite database share both data and identity while any
Runtime connection keeps that database alive; after the last connection closes, reopening creates new data and identity.
SQLite storage classification uses the dialect's effective connection arguments and the decoded SQLite URI, including
supported true spellings (true, 1, yes, on), percent-encoded :memory: paths, and the built-in vfs=memdb
in-memory filesystem. Empty-path file URIs such as
file:?uri=true and file:?cache=shared&uri=true create connection-local temporary databases, not durable files.
Classification also honors SQLite's decoded NUL termination for filenames and query parameter names/values:
file:%00tail?uri=true is temporary, an encoded :memory: followed by %00 remains memory storage, and
mode=memory%2500tail or mode%2500tail=memory in a SQLAlchemy URL still selects native memory mode. Only an exact lowercase file: prefix enables
SQLite URI interpretation; uppercase schemes, leading spaces, and literal filename controls are not normalized.
SQLiteConfig.is_in_memory distinguishes memory storage; SQLiteConfig.is_persistent excludes both memory and temporary
storage. Pooling keeps one connection for nonpersistent storage; offline maintenance, cursor-secret persistence, and
subprocess workers consume that same persistence classification.
The unified migration implementation from RFC #1771 currently
covers only a registered four-table Artifact bundle. It does not manage pc_server_identity, gate ordinary Server
startup, or establish complete Server readiness; its maintenance commands reject a complete business database with
unmanaged tables. Do not use that partial bundle to migrate a Server database.
When unified migration takes ownership of the complete Server schema, identity table creation must move from startup
DDL into an immutable managed revision, with schema verification before Runtime composition. If discovery is already
released, the supported historical baseline must include the existing identity table and preserve its singleton value;
if still unmerged at framework enablement, discovery must ship that revision alongside the model. Deployment identity
remains distinct from pc_schema_revision, and schema adoption or upgrades must not rotate server_id. Clone rotation
remains an explicit offline operation. No independent schema-version or migration-readiness marker is added for identity.
Treat a restored backup as the same deployment and keep its ID. When a backup is used to create an independent clone, stop every Server process using the clone database and rotate only the clone:
uv run powercontext server identity-reset --env-file /path/to/clone.env --maintenance-confirmedThe command refuses in-memory and temporary databases and requires the explicit maintenance confirmation. It cannot detect active
replicas, so stopping them is an operator precondition. Logical application-data imports do not copy the identity unless
the pc_server_identity table itself is included.
Python Client
Install the Client role for the SDK:
uv add "powercontext[client]"PowerContextClient is async-native and uses the generated request and response models:
from powercontext.http import SearchMemoryRequest
from powercontext.client import PowerContextClient
async def search() -> None:
async with PowerContextClient("http://127.0.0.1:8000") as client:
server_info = await client.get_server_info()
capabilities = await client.get_capabilities()
result = await client.search_memory(
SearchMemoryRequest(
scope_id="project-alpha",
query="composition root",
limit=10,
mode="auto",
)
)
print(server_info.model_dump())
print(capabilities.model_dump())
print(result.model_dump())The client validates successful responses with Pydantic. Transport failures, invalid responses, and structured Server
errors are exposed as distinct exceptions from powercontext.client.
CLI
Add the CLI extra to expose the installed Client command:
uv add "powercontext[cli,client]"The client command provides process and capability checks:
uv run powercontext live
uv run powercontext ready
uv run powercontext capabilities
uv run powercontext --json capabilitiesUse POWERCONTEXT_CLIENT_SERVER_URL and POWERCONTEXT_CLIENT_TIMEOUT for client defaults.
The CLI discovers command groups from installed roles. powercontext[cli] provides the Builtin command by default;
Client and Server commands appear only when their role extras are also installed.
MCP
MCP is enabled by default and mounted at /mcp. Disable it without changing the HTTP API:
export POWERCONTEXT_SERVER_MCP_ENABLED="false"To change the mount path:
export POWERCONTEXT_SERVER_MCP_PATH="/agent"The MCP projection includes the agent-facing Memory operations for search, listing, reading, remembering, revising, and retiring entries, plus Candidate Review operations for listing, reading, approving, rejecting, and revising Candidates. Health, capability, Source capture, Experience, flush, and change-history endpoints remain HTTP-only.
HTTP and MCP share the same Server application and Runtime binding. A request made through either transport therefore uses the same scope isolation, validation, concurrency checks, and persistence behavior.
Programmatic composition
Applications that host FastAPI themselves can build the same service:
from powercontext.server.factory import create_server_app
from powercontext.server.settings import ServerSettings
app = create_server_app(settings=ServerSettings())create_server_app() owns the built-in Runtime lifecycle. Tests and embedding applications may inject a
candidate_pipeline or embedding_model without replacing that lifecycle.

