Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "mcpx",
"version": "0.18.1",
"version": "0.18.2",
"license": "MIT",
"bin": {
"mcpx": "./src/main.ts"
Expand Down
10 changes: 5 additions & 5 deletions src/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,18 +17,18 @@ The surface depends on the registry, so read only the slice you need: `mcpx @sch
## Calling a tool — `.<server>.<tool>`

- Call as `mcpx <server>.<tool> "<object>"`. The object is the complete tool input: one quoted token, or the whole object as YAML/JSON5 from `@file` or stdin (`-`).
- Put multi-line text in a quoted heredoc with `|` block scalars. Field values are literal: never pass `-` or `@path` as a field value, and never mix the object with `--flag`s. Quote scalars YAML would retype (`'1.10'`, `'012'`, `'true'`). A file or stdin starting with `{` is read as JSON5.
- Put multi-line text in a quoted heredoc with `|` block scalars. Field values are literal: no field takes `-` or `@path`. Quote scalars YAML would retype (`'1.10'`, `'012'`, `'true'`). A file or stdin starting with `{` is read as JSON5.
- Tool results may include `$notifications` (progress, server events). Ignore them unless the task depends on them; format and special cases: `mcpx @skill references/notifications.md`.

## Registering servers — `@add`, `@login`, `@remove`
## Registering servers — `.{"@add","@login","@remove"}` (quote the `@`)

Only when the user asks. `@add` takes an HTTP `url` (default) or `transport: 'stdio'` with `command`/`args`; after that both behave identically. Bearer auth goes in `bearer`, and `env:NAME` keeps the secret out of the registry (an array round-robins credentials). `@login "{ name: '<server>' }"` needs a TTY; otherwise ask the user to run it. Input shapes: `mcpx @add --help`.
Only when the user asks. After `@add`, HTTP and stdio servers behave identically. Register a bearer token as `env:NAME` so the secret stays out of the registry and argv. `@login "{ name: '<server>' }"` needs a TTY; otherwise ask the user to run it.

## Project-local skills — `@skill-install`
## Project-local skills — `."@skill-install"`

When the user wants a project to expose only an approved set of servers, `mcpx @skill-install "{ servers: 'posthog,sentry' }"` writes `.agents/skills/mcpx/` (router plus install and server-recovery references). `{ show: 'sentry' }` prints a one-server skill to stdout without writing files. It does not replace `@add`.

## Daemon — `@daemon`
## Daemon — `."@daemon"`

`mcpxd` keeps sessions warm and is normally invisible. For stuck sessions, surprising eviction or schema drift read `mcpx @skill references/daemon.md` before filing an issue.

Expand Down
33 changes: 27 additions & 6 deletions src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -64,20 +64,42 @@ const outputContext = s(
const addInput = s(
v.object({
name: v.pipe(v.string(), v.description('Global server name')),
transport: v.optional(v.picklist(['http', 'stdio'])),
transport: v.optional(
v.pipe(
v.picklist(['http', 'stdio']),
v.description('Default http; stdio needs command'),
),
),
url: v.optional(
v.pipe(
v.string(),
v.url(),
v.description('MCP Streamable HTTP endpoint URL'),
),
),
bearer: v.optional(v.union([v.string(), v.array(v.string())])),
bearer: v.optional(
v.pipe(
v.union([v.string(), v.array(v.string())]),
v.description(
"Token or env reference ('env:NAME', kept live); several round-robin. Prefer env:NAME, or pass the object via stdin so a literal stays off argv",
),
),
),
command: v.optional(
v.pipe(v.string(), v.description('Stdio MCP server command')),
),
args: v.optional(v.union([v.string(), v.array(v.string())])),
env: v.optional(v.record(v.string(), v.string())),
args: v.optional(
v.pipe(
v.union([v.string(), v.array(v.string())]),
v.description('Stdio command arguments'),
),
),
env: v.optional(
v.pipe(
v.record(v.string(), v.string()),
v.description('Environment for the stdio process'),
),
),
}),
)

Expand Down Expand Up @@ -234,7 +256,6 @@ function buildRouter(registry: RegistryView, schemas?: SchemaResync): Router {
'@remove': c
.meta({
description: 'Remove a global MCP server and its cached credentials.',
examples: [`mcpx @remove "{ name: 'posthog,sentry' }"`],
})
.input(removeInput),
'@login': c
Expand All @@ -254,14 +275,14 @@ function buildRouter(registry: RegistryView, schemas?: SchemaResync): Router {
}),
server: c.meta({
description: 'Run the local mcpxd daemon server.',
hidden: true,
}),
},
),
'@skill-install': c
.meta({
description:
'Generate a project skill or print a temporary server skill for agents.',
examples: [`mcpx @skill-install "{ servers: 'posthog,sentry' }"`],
})
.input(skillInput),
}
Expand Down
Loading