Introduction
1muse is a credential broker. Your connector declares the upstream calls it needs to make, your user grants permission to make them, and 1muse performs each call with a credential the agent never sees. What comes back to the agent is a result, not a key.
There are two roles. A human owns credentials and decides what an agent may do with them. An agent invokes named capabilities and receives results. The agent never holds blanket access to a vault, and there is no API that returns a stored credential value.
Install
npx @1muse/cli init # scaffold a connector npm install @1muse/connector # the SDK
Node 20 or newer. The CLI never asks for an upstream credential — those arrive from your users and go straight into their vaults.
Vaults
A vault holds one end user's secrets for one connector. Each secret is sealed with a per-user data key, which is itself wrapped by a key in a cloud HSM, so a database dump alone is inert.
- Envelope encryption with per-user data keys
- Bring your own KMS on Studio and above — you hold the root
- Versioning, scheduled rotation, expiry and max-use counts
- No read API, for you or for our support team
Bindings
A binding is a declared upstream call: a method, a path, an argument schema and the credential it needs. The agent invokes it by name. Because arguments are typed, a malformed call fails at the edge rather than reaching your upstream.
"acme.invoice.pay": { "call": "POST /v2/invoices/:id/pay", "uses": "acme_api_key", "scope": "write" }
Grants
Nothing is reachable until a person grants it. A grant names the subject, the bindings, the limits and the expiry. Every brokered call carries a reference back to one.
const url = await broker.grantUrl({ subject: "user_8812", bindings: ["acme.invoice.list", "acme.invoice.pay"], expires: "90d" });
Revoking is the inverse, and it does not disturb your other users or require rotating the upstream secret.
await broker.revoke({ grant: "gr_9f2a" });
Policy
Policy is declared per binding in the manifest, not in your application code, so a reviewer can read one file and know what the connector may do.
| Key | Effect |
|---|---|
maxPerCall | Hard ceiling on a value argument, in minor units. |
maxPerDay | Rolling 24-hour ceiling across one grant. |
approvalOver | Above this, park the call and ask the human who signed the grant. |
argsFrom | "user" refuses arguments that originated in content the agent merely read. |
allowHosts | Restrict egress to named hosts. |
window | Time-of-day window in which the binding may run. |
argsFrom: "user" means an argument traced to browsed
content is refused rather than executed.
Ledger
Every decision is written to an append-only ledger in which each entry seals the one before it, so silent edits are detectable rather than merely discouraged.
- Grant, agent identity, binding, arguments and upstream status per entry
- Stream to your SIEM, or export a signed bundle
- Retention: 7 days on Free, 90 on Builder, a year on Studio
Connector SDK
The SDK reads 1muse.connector.json at start-up and gives you one typed method per binding.
import { broker } from "@1muse/connector"; const receipt = await broker.invoke({ binding: "acme.invoice.pay", onBehalfOf: grant.subject, args: { invoiceId: "in_8812", amount: 24000 } });
Call outcomes
Every call resolves to one of three outcomes. Handle all three — a hold is not an error, and treating it as one is the most common integration mistake.
switch (receipt.status) { case "allowed": return receipt.result; case "held": return askUser(receipt.approvalUrl); case "denied": return explain(receipt.reason); }
| Status | Meaning | Billed |
|---|---|---|
allowed | The upstream ran; result holds the response. | Yes |
held | Over a threshold; approvalUrl is where the human decides. | No |
denied | No grant, or policy refused it; reason says which. | No |
Manifest reference
| Field | What it does |
|---|---|
connector | Stable identifier. Appears in every ledger entry. |
surfaces | Where it may be invoked: muse.app, muse.code, mcp. |
credentials | Named secrets the connector needs, with type and rotation interval. |
bindings | The callable capabilities. One entry per upstream call. |
bindings.*.call | Method and path. Path parameters use :name. |
bindings.*.uses | Which credential to unwrap. Omit for unauthenticated calls. |
bindings.*.scope | read or write. Granted separately. |
bindings.*.policy | The policy block described above. |
MCP server
The same bindings are exposed over the Model Context Protocol, so Muse Code and other MCP clients get an identical surface with no second integration.
{
"mcpServers": {
"1muse": {
"command": "npx",
"args": ["-y", "@1muse/mcp"],
"env": { "ONEMUSE_AGENT_KEY": "omk_your_agent_key" }
}
}
}
The agent key scopes the client to the grants it has been given. On its own it unwraps nothing.
Errors
| Code | Meaning |
|---|---|
no_grant | No grant covers this binding for this subject. |
grant_expired | The grant existed but has passed its expiry. |
cap_exceeded | An argument exceeded maxPerCall or maxPerDay. |
arg_provenance | An argument was traced to browsed content on a argsFrom: "user" binding. |
schema_invalid | Arguments failed the binding's schema; nothing was sent upstream. |
upstream_error | The upstream returned a failure; its status is on receipt.upstream. |
Rate limits
Limits apply per grant, not per connector, so one noisy user cannot exhaust another's budget.
| Plan | Brokered calls | Burst |
|---|---|---|
| Free | 2,500 / month | 20 / minute |
| Builder | 50,000 / month | 120 / minute |
| Studio | 500,000 / month | 600 / minute |
| Enterprise | 5,000,000 / month | Negotiated |