SOLWYN
Commands

mcp / mcp-config

The local MCP server, its 33-read and 37-guardrails profiles, authentication, work bounds, and launch descriptor.

solwyn mcp serves Solwyn's operations as tools to any MCP client over stdio. solwyn mcp-config prints the command and arguments a client needs to launch it. solwyn doctor --mcp checks that the wiring works. For how an agent should use the tools, see Agent integration.

mcp

Terminal
solwyn [--project <project_id>] [--api-url <url>] mcp [--profile read|guardrails]
OptionTypeDefaultPurpose
--profileread | guardrailsguardrailsThe fixed tool surface for this launch.
Contract
Authresolved per tool call, never at startup
Exit codes0 clean shutdown · 1 startup or protocol failure · 2 usage
Transportstdio only; stdout is reserved for JSON-RPC framing

Put the global --project and --api-url before mcp and --profile after it. The output flags (--json, --format, --no-color) are accepted and ignored. The server advertises tools only — no prompts, no resources — and the profile is fixed for the life of the process; no tool argument can change it.

Credentials are read from SOLWYN_API_KEY or the OS keychain on every tool call, so a rotated key is picked up mid-session and listing tools never touches a credential. An empty or malformed SOLWYN_API_KEY blocks keychain fallback rather than silently selecting another identity.

Profiles

ProfileToolsUse when
read33 read-only toolsObserve projects, accounts, costs, billing estimates, team access and delivery. The default for setup, mcp-config, doctor --mcp, and the shipped example clients.
guardrailsAll 37, adding budget_check, budget_confirm, budget_check_batch, record_callThe agent makes un-instrumented provider calls itself and must run the check → confirm loop. The default for bare solwyn mcp.

Recommend --profile read unless the agent genuinely spends. A tool excluded by the profile is not merely denied — it is never registered, so calling it fails as an unknown tool before any argument, credential, or network is touched. Profiles expose tools; they never grant permissions. A full-scope key does not promise that a future budget decision will allow spend.

The tool catalogue

ToolCLI equivalentMutatesCredential
budget_statusbudget statusnoeither
budget_checkbudget checkyesfull-scope project key
budget_confirmbudget confirmyesfull-scope project key
budget_check_batchbudget check --batchyesproject key; read-only suffices for recover_only
record_callrecordyesfull-scope project key
get_project_statusstatusnoeither
get_forecastforecastnoeither
get_costscostsnoeither; account=true requires JWT
get_cost_totalcosts totalnoeither
list_budget_rulesbudget rules listnoeither; with_last_fired=true requires JWT
list_tagstags listnoeither; Team and above
list_tag_valuestags valuesnoeither; Team and above
list_agent_runsruns listnoeither
get_agent_runruns shownoeither
list_alert_eventsalerts listnoeither; account: true requires JWT
list_projectsprojects listnoJWT
get_overviewoverviewnoJWT
list_cost_eventscosts eventsnoeither
get_cost_baselinecosts baselinenoeither
get_unit_economicscosts unit-economicsnoeither
get_cost_driftcosts driftnoeither
list_priced_modelscosts priced-modelsnoeither
simulate_costscosts simulatenoeither
list_provider_failoversproviders failoversnoeither
list_untracked_surfacesproviders untrackednoeither
list_audit_eventsauditnoJWT
plan_statusplannoJWT or project key with account context; no project required
plan_catalogplan listnoJWT or project key with authenticated user context; no project required
get_whoamiwhoaminoeither; a key returns local context only
get_account_phoneaccount phone shownoJWT
list_alert_activityalerts activitynoJWT
list_open_alert_deliveriesalerts pendingnoJWT
budget_uncountedbudget uncountednoeither
get_account_alertalerts account shownoJWT; optional with_last_fired
plan_previewplan change --dry-runnoJWT at any account role; no project required
list_team_membersteam members listnoJWT at any account role; no project required
list_team_invitesteam invites listnoowner/admin JWT; no project required

Every read tool is annotated readOnlyHint: true, idempotentHint: true; the four writers carry destructiveHint: true. Tool inputs mirror the CLI flags in snake case — get_costs takes the full shared cost-filter set and from_/to windows, list_tag_values takes key, prefix, limit, cursor, and so on — and every input schema is closed, so an unknown key is rejected as invalid_arguments. The three budget tools' descriptions are generated from the same text as solwyn agent-context, so the MCP guidance and the CLI brief cannot drift apart.

All 33 reads appear in both profiles. The four writers appear only in guardrails; recovery-only batch access still requires that profile. Reads carry destructiveHint: false; writers carry readOnlyHint: false and idempotentHint: false. All tools carry openWorldHint: true because they contact Core. Annotations describe behavior and do not enforce authorization.

plan_preview(tier="team", interval="year") uses a read-only POST, creates no invoice or subscription change, and returns solwyn.plan.preview.v1 with immediate/scheduled mode, dates, signed integer cents, currency and proration lines. An estimate is not a price lock. Cost simulation and opt-in latest-alert lookup also use read-only POSTs.

Billing, team/member writes, account rename/recovery and invitation token/password workflows remain CLI-only. Rule, channel, project, key and alert writes also remain CLI/dashboard operations.

Selection and authorization

Credential order is environment project key, stored project key, then stored JWT. A selected key masks JWT and a JWT-only tool refuses it; the server never silently switches identities. Unset SOLWYN_API_KEY and deliberately use logout then login to clear a stored key when user login is needed.

For project reads, an explicit project_id overrides launch --project, then SOLWYN_PROJECT_ID, then default_project. Writes always use the key's own project. Project selection does not change key scope, account role or account membership. Core also checks access and plan entitlements.

get_costs(account=true) defaults to project grouping, requires JWT and rejects explicit project_id; configured default projects are irrelevant. Only model, provider, modality and preset/paired custom windows apply in account mode. list_alert_events(account=true) reads account-scope history and ignores project_id; list_alert_activity reads all projects plus account scope. Roster reads allow any member; invitation listings require owner/admin and preserve expired open rows and delivery statuses. Listing or resending an invitation does not prove email delivery.

MCP 2026-07-28 discovery advertises ttlMs=60000, cacheScope="private"; legacy clients receive the same tools without those fields. Hosts may cache discovery for one minute per launch/profile. Tool results have no cache hint: discovery freshness does not cache credentials, authorize spend or extend reservations.

The result envelope

Every tool returns one typed object, serialized identically into the text content and the structured content of the result:

{"schema":"solwyn.mcp.budget-check.v1","ok":true,"data":{"allowed":false,"reservation_id":null,"denied_by_period":"monthly","call_id":"…","recorded":{"status":"ingested"}},"error":null}
{"schema":"solwyn.mcp.budget-status.v1","ok":false,"data":null,"error":{"code":"authentication_required","message":"Solwyn authentication is required.","hint":"Configure a project key or run solwyn login, then retry.","status_code":null}}

isError is set exactly when ok is false. Two consequences matter for a model:

  • A budget denial is a successful decision, not an error: ok: true, isError: false, data.allowed: false. Fail-open is allowed: true with reservation_id: null, and a stopped run is an ordinary denial. Denials record attribution by default unless no_record is set.
  • Error messages are fixed strings. Server error codes pass through only from an allowlist; anything else becomes api_error. Validation hints name a schema path, never an input value. Tracebacks, raw server text, secrets, and the names of unknown methods are never returned.

An HTTP-200 result whose attribution recording was rejected or failed is downgraded to ok: false with a recording_* code while keeping data, so a settled reservation is never mistaken for an unsettled one.

Bounded work

Every call runs inside fixed limits. There is no per-session cap and no option to change these:

LimitValue
Useful-work deadline30 seconds
Pages fetched for a paginating tool10
Aggregate HTTP response bytes1 MiB
Encoded request body4 MiB
Complete tool result2 MiB
Batch size1 to 32 checks
Continuation cursor4,096 characters

Hitting a limit returns an ordinary tool error — operation_deadline, page_limit, response_size_limit, result_size_limit — but never loses identities. An oversized result is replaced by the error plus a compact recovery object: for a mutating tool, the operation id, per-item states, reservation and call ids, and the settlement and recording status; for a read, the cursor to resume from. Cancellation or a closed stdin stops future requests and pages but cannot undo a request the API already admitted.

budget_check_batch extends this with a durable journal: supply a caller-retained UUIDv7 operation_id before calling, and if the reply is lost, call again with recover_only: true to read the outcome without admitting anything new. Reservations expire 300 seconds after they were checked; journal entries expire after 24 hours.

Cursor listings retain their first unread cursor on a later-page error. This bounded MCP behavior differs from CLI --all, which emits no partial success. See bounded work and journal recovery, observed media recovery, and service capacity and uncertain writes.

mcp-config

Print the command and argument array a client should use to launch the server. It writes no files, reads no credential, and makes no network call.

Terminal
solwyn [--project <project_id>] [--api-url <url>] [--json] mcp-config [--executable <path>] [--profile read|guardrails]
OptionTypeDefaultPurpose
--executablepaththis installation's solwynAn explicit installed executable. Never a PATH lookup.
--profileread | guardrailsreadProfile to bake into the descriptor.
Contract
Authnone; no credential lookup
Exit codes0 descriptor emitted · 1 executable unavailable · 2 usage
JSON schemasolwyn.mcp-config.v1
Terminal
$ solwyn --json --project proj_0123456789abcdef01234567 mcp-config
{"schema":"solwyn.mcp-config.v1","command":"/absolute/path/to/solwyn","args":["--project","proj_0123456789abcdef01234567","--api-url","https://api.solwyn.ai","mcp","--profile","read"]}

The descriptor is host-neutral; adapt command and args to your client's configuration format. It never contains a key — supply credentials through the OS keychain or the host's environment block. See Agent integration for ready-to-paste examples and doctor --mcp to verify the result.

  • Agent integration — the one rule, the guardrail loop, client wiring, and diagnostics
  • budget — every option the budget tools mirror, including recovery after a lost reply
  • doctor — --mcp launches the server in isolation and checks discovery and a read

On this page