Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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
4 changes: 4 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format

## [Unreleased]

### Added

- [#40](https://github.com/mohanagy/miftah/issues/40) Added an owner-readable Miftah 0.5 feature and usage guide that distinguishes the 0.5 onboarding/profile-management delta from capabilities first shipped in 0.4, maps each outcome to production-bound CLI or Console entry points, and retains the package's OAuth, active-session, provider-ownership, pre-1.0, and incomplete external-validation boundaries.

### Changed

- [#290](https://github.com/mohanagy/miftah/issues/290) Redesigned the README as a concise product front door: first-screen fit guidance, one connector with named profiles, one safe GitHub first-success path, distinct secret/native-OAuth/upstream-owned-OAuth routes, visible client/wizard/Console choices, and progressively disclosed security, architecture, reference, and troubleshooting links. External evaluator acceptance remains open and is not claimed by this documentation change.
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,8 @@ Miftah itself has no cloud service or telemetry. It adds local profile selection

> **Status:** Miftah is experimental and pre-1.0. Interfaces and security behavior may change between minor versions. External multi-account and returning-user validation in [#25](https://github.com/mohanagy/miftah/issues/25) and [#88](https://github.com/mohanagy/miftah/issues/88) remains open.

Already using Miftah? See [What is in 0.5 and how to use it](docs/whats-new-in-0.5.md) for the release's guided setup, profile-management, Console, OAuth, and upgrade paths.

## Is Miftah for you?

Use Miftah when:
Expand Down
171 changes: 171 additions & 0 deletions docs/whats-new-in-0.5.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,171 @@
# What is in Miftah 0.5

Install `@lubab/miftah@0.5.0` when you want Miftah to guide setup instead of assembling a multi-account configuration by hand:

```bash
npm install -g @lubab/miftah@0.5.0
miftah version
```

The short version of 0.5.0 compared with 0.4.0 is: Miftah now has guided and resumable setup, safer setup previews, account-profile maintenance commands, client-entry import, and a complete multi-account Google Search Console onboarding path.

Native OAuth and the optional Console first shipped in 0.4.0. 0.5.0 makes them easier to discover, configure, and maintain; it does not introduce universal OAuth support or a hosted Miftah service.
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved

## The 60-second feature map

| What you want to do | What 0.5 adds | Start here |
| --- | --- | --- |
| Create a configuration from what you already have | An outcome-first wizard for a known connector, remote HTTPS MCP, local executable, browser sign-in, or one existing client entry | `miftah setup` |
| Review setup before writing | A non-secret, no-write structural plan | `miftah setup --plan` with the complete inputs for your setup path |
| Continue an interrupted setup choice | A private, bounded checkpoint that stores no URL, path, command, credential, or browser state | `miftah setup --resume`, or `miftah setup --discard-draft` |
| Add another supported account | Guarded profile addition for the reviewed Google Search Console adapter or a narrow local environment-backed configuration | `miftah setup --add-profile` |
| See and maintain configured accounts | List, change the durable default, describe, rename, remove, or safely test one profile | `miftah profile list --config CONFIG_FILE` |
| Use the browser instead of the terminal wizard | The same reviewed first-run and account-management paths in the foreground local Console | `miftah dashboard` |

## 1. Start with the guided setup

Run:

```bash
miftah setup
```

The wizard asks what you already have:

- **connector** — a reviewed built-in connector or exact-pinned package;
- **remote HTTPS** — a strict Streamable HTTP endpoint without contacting it during generic setup;
- **local executable** — one literal executable plus argument array, with no shell;
- **browser sign-in** — a remote HTTPS MCP that advertises Miftah's supported standards-based OAuth flow;
- **import** — one explicitly selected entry from one existing client JSON file.

The wizard asks for environment-variable names and non-secret metadata, not token or password values. It validates the complete candidate before publication and prints client configuration for manual review. Miftah does not silently edit Claude Desktop, Claude Code, Cursor, or VS Code.

After merging the generated client entry, restart the MCP client. A running client process does not automatically adopt configuration or profile changes made later.

## 2. Preview a complete setup without writing

For example, this Google Search Console plan is safe to paste even before the referenced client-secrets file exists:

```bash
miftah setup gsc --preset google-search-console \
--oauth-client-secrets-file "$HOME/.config/gsc/client-secrets.json" \
--output "$HOME/.config/miftah/gsc.json" \
--plan
```

The plan does not write a configuration or start an upstream. It can identify the requested publication target, but its configuration summary omits credential paths, endpoints, launch arguments, credential references, OAuth details, and secret values.

When the real inputs are ready, repeat the command without `--plan` to create the new file. Add `--verify` only when you want a reviewed adapter's declared read-only readiness check to run after publication.

If interactive setup stops after saving its bounded connector choice, continue with:

```bash
miftah setup --resume
```

Discard that saved choice without creating a configuration with:

```bash
miftah setup --discard-draft
```

All connection details must be entered again after resume; the checkpoint does not store them.

## 3. Import one existing client entry

Choose **import** in `miftah setup`, provide one absolute client JSON path, and select one listed entry. Miftah displays entry names only. It does not print the source command, arguments, environment values, headers, or credentials, and it never modifies the source client file.

The import path accepts only a supported local STDIO entry or a credential-free HTTPS remote entry. It does not guess authentication ownership. Use `--import-file` and `--import-entry` for the equivalent explicit noninteractive path; review it first with `--plan`.

## 4. Set up and maintain multiple Google accounts

Google Search Console is the reviewed provider-adapter example in 0.5:

```bash
miftah setup gsc --preset google-search-console
```

The guided flow collects each profile name and asks which profile should be the durable default. Every generated configuration/profile pair receives a distinct `GSC_CONFIG_DIR`. The `mcp-search-console` upstream owns browser login, refresh, reauthentication, revocation, and the token cache inside that directory. Miftah never reads or copies the upstream-owned token cache.

Add a returning account to an existing reviewed configuration with:

```bash
miftah setup --add-profile \
--config "$HOME/.config/miftah/gsc.json" \
--profile google-personal \
--oauth-client-secrets-file "$HOME/.config/gsc/personal-client-secrets.json" \
--verify
```

This is a configuration mutation, not a preview. It adds one isolated profile through the reviewed adapter contract, records a redacted lifecycle event, and runs only the declared `get_capabilities` readiness probe when `--verify` is present. That probe is health evidence; it does not prove the authorized Google account or property.

Read the [provider-adapter guide](provider-adapters.md) for prerequisites, service-account alternatives, cache ownership, and recovery.

## 5. Inspect and maintain account profiles

Use `CONFIG_FILE`, `PROFILE_NAME`, and the other uppercase values below as literal safe placeholders until you substitute your reviewed values:

| Task | Command |
| --- | --- |
| List non-secret profile metadata | `miftah profile list --config CONFIG_FILE` |
| Change the durable default for future sessions | `miftah profile set-default --config CONFIG_FILE --profile PROFILE_NAME` |
| Add a non-secret description | `miftah profile set-description --config CONFIG_FILE --profile PROFILE_NAME --description DESCRIPTION_TEXT` |
| Rename a profile and its configuration-owned references | `miftah profile rename --config CONFIG_FILE --profile PROFILE_NAME --new-profile NEW_PROFILE_NAME` |
| Remove a profile and reassign durable references | `miftah profile remove --config CONFIG_FILE --profile PROFILE_NAME --replacement-profile REPLACEMENT_PROFILE` |
| Run one adapter-declared read-only readiness check | `miftah profile test --config CONFIG_FILE --profile PROFILE_NAME` |

`list` does not resolve credentials or start an upstream. The configuration-changing commands validate first, use guarded replacement and recovery backup behavior, and preserve the documented credential and provider-cache boundaries. Profile changes affect future MCP sessions; restart the MCP client when you need a new session to observe them.

## 6. Pick the correct authentication owner

| Authentication path | What Miftah owns | Where to begin |
| --- | --- | --- |
| API key or secret reference | Resolving a configured profile-scoped reference and redacting the value | Run `miftah setup` and provide an environment-variable name or another supported secret reference. |
| Native OAuth | Supported remote discovery, browser authorization, OS-vault storage, refresh, reauth, and exact local disconnect | Use `miftah setup --native-oauth` only with a real HTTPS MCP endpoint that satisfies the documented standards. |
| upstream-owned OAuth | Passing reviewed configuration to the upstream while leaving its browser and cache lifecycle alone | Use a reviewed adapter such as Google Search Console and follow its upstream login. |

Miftah does not support OAuth for every MCP server or provider. A successful login, resolvable credential, or profile label is not proof of scopes or account identity. See the [OAuth guide](oauth-support.md) for native connection lifecycle commands and the exact support matrix.

## 7. Use the optional local Console

Run:

```bash
miftah dashboard
```

The Console is a foreground, literal-loopback browser UI for reviewed setup, profile maintenance, connection health, and supported OAuth lifecycle work. It is optional, does not run as a daemon, never exposes raw credentials, and cannot take over an already-running MCP client session.

Use `miftah dashboard --no-open` when you want the local URL printed without opening a browser. See the [Console guide](console-api.md) for its one-use bootstrap and authenticated local-control boundary.

## Reliability and security changes in 0.5

The release also:

- refuses Windows STDIO command shims and shell executables instead of silently falling back to `cmd.exe`;
- patches the MCP SDK/Hono runtime dependency chain and scoped development-toolchain advisories;
- hardens Windows configuration identity and Console ACL checks;
- improves macOS OAuth locking, audit locking, and bounded upstream process-tree cleanup.

These changes do not weaken redaction, audit finalization, Windows ACL verification, process containment, or existing timeouts. See the [full changelog](../CHANGELOG.md) for the issue-by-issue details.

## Upgrade and validation

Version 0.4 already wrote configuration format v3, so a normal 0.4 configuration does not need a format change merely because the package becomes 0.5. Validate the exact file and its runtime readiness after upgrading:

```bash
miftah validate --config "$HOME/.config/miftah/miftah.json"
miftah doctor --config "$HOME/.config/miftah/miftah.json"
```

If your configuration is still v1 or v2, use the dry-run-first migration path in the [CLI reference](cli.md) rather than editing version fields by hand.

## What remains intentionally incomplete

- External multi-account and returning-user validation is still open in [#25](https://github.com/mohanagy/miftah/issues/25) and [#88](https://github.com/mohanagy/miftah/issues/88).
- Miftah is experimental and pre-1.0; minor releases can contain documented incompatible changes.
- Native OAuth is deliberately narrow. Provider-specific and local OAuth often remains upstream-owned.
- Miftah cannot prove an account identity unless the selected upstream exposes stable, bounded identity evidence.
- Generated client snippets are manual handoff artifacts. Miftah does not silently edit client settings or replace a running MCP session.

For every command and option, use the [CLI reference](cli.md). For the product model and first working connector, return to the [README](../README.md).
131 changes: 131 additions & 0 deletions tests/v050-feature-guide-contract.test.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
import { existsSync, readFileSync } from "node:fs";
import { describe, expect, it } from "vitest";
import { CLI_COMMANDS, renderCommandHelp, type CliCommand } from "../src/cli/parse.js";

const guideUrl = new URL("../docs/whats-new-in-0.5.md", import.meta.url);
const readme = readFileSync(new URL("../README.md", import.meta.url), "utf8");
const changelog = readFileSync(new URL("../CHANGELOG.md", import.meta.url), "utf8");
const packageManifest = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")) as {
version: string;
};

function readGuide(): string {
return existsSync(guideUrl) ? readFileSync(guideUrl, "utf8") : "";
}

function documentedMiftahCommands(markdown: string): string[] {
const bashBlocks = [...markdown.matchAll(/```bash\n([\s\S]*?)```/gu)].map((match) => match[1]!);
const fencedCommands = bashBlocks.flatMap((block) =>
block
.replace(/\\\n\s*/gu, " ")
.split("\n")
.map((line) => line.trim())
.filter((line) => line.startsWith("miftah "))
);
const inlineCommands = [...markdown.matchAll(/`(miftah [^`\n]+)`/gu)].map((match) => match[1]!);
return [...new Set([...fencedCommands, ...inlineCommands])];
}

describe("Miftah 0.5 owner guide", () => {
it("publishes a linked, release-aligned explanation of the product delta", () => {
const guide = readGuide();

expect(guide).not.toBe("");
expect(guide.split("\n").length).toBeLessThanOrEqual(220);
expect(guide).toContain("# What is in Miftah 0.5");
expect(guide).toContain(`Install \`@lubab/miftah@${packageManifest.version}\``);
expect(guide).toContain("0.5.0 compared with 0.4.0");
expect(guide).toContain("guided and resumable setup");
expect(guide).toContain("Native OAuth and the optional Console first shipped in 0.4.0");
expect(guide).toContain("0.5.0 makes them easier to discover, configure, and maintain");
expect(readme.split("\n").slice(0, 80).join("\n")).toContain(
"[What is in 0.5 and how to use it](docs/whats-new-in-0.5.md)"
);
});

it("maps the main 0.5 outcomes to exact safe starting commands", () => {
const guide = readGuide();

for (const text of [
"miftah setup",
"miftah setup gsc --preset google-search-console",
"--plan",
"--resume",
"--discard-draft",
"--import-file",
"--import-entry",
"miftah dashboard",
"miftah setup --add-profile",
"miftah profile list",
"miftah profile set-default",
"miftah profile set-description",
"miftah profile rename",
"miftah profile remove",
"miftah profile test"
]) {
expect(guide).toContain(text);
}

expect(guide).toContain("The plan does not write a configuration or start an upstream.");
expect(guide).toContain("Miftah never reads or copies the upstream-owned token cache.");
});

it("keeps the authentication, active-session, and validation boundaries honest", () => {
const guide = readGuide();

expect(guide).toContain("Miftah does not support OAuth for every MCP server or provider.");
expect(guide).toContain("Native OAuth");
expect(guide).toContain("upstream-owned OAuth");
expect(guide).toContain("API key or secret reference");
expect(guide).toContain("restart the MCP client");
expect(guide).toContain("External multi-account and returning-user validation is still open");
expect(guide).toContain("[#25]");
expect(guide).toContain("[#88]");
expect(guide).toContain("[CLI reference](cli.md)");
expect(guide).toContain("[OAuth guide](oauth-support.md)");
expect(guide).toContain("[provider-adapter guide](provider-adapters.md)");
expect(guide).toContain("[full changelog](../CHANGELOG.md)");
});

it("binds every documented Miftah command and flag to generated CLI help", () => {
const commands = documentedMiftahCommands(readGuide());
expect(commands.length).toBeGreaterThan(5);

for (const line of commands) {
const match = /^miftah\s+([a-z][a-z-]*)(?:\s+([a-z][a-z-]*))?/u.exec(line);
expect(match, `could not parse guide command: ${line}`).not.toBeNull();
const primary = match![1]!;
const command = (primary === "connection" || primary === "auth" || primary === "profile"
? `${primary} ${match![2]}`
: primary) as CliCommand;
expect(Object.keys(CLI_COMMANDS), `unknown guide command: ${command}`).toContain(command);
const supportedFlags = new Set(renderCommandHelp(command).match(/--[a-z][a-z-]*/gu) ?? []);
for (const flag of [...line.matchAll(/(?:^|\s)(--[a-z][a-z-]*)/gu)].map((flagMatch) => flagMatch[1]!)) {
expect(supportedFlags, `unsupported guide flag for ${command}: ${flag}`).toContain(flag);
}
}
});

it("keeps fenced commands paste-safe and records the guide under issue 40", () => {
const guide = readGuide();
const bashBlocks = [...guide.matchAll(/```bash\n([\s\S]*?)```/gu)].map((match) => match[1]!);

for (const block of bashBlocks) {
expect(block).not.toMatch(/[<>]/u);
}
expect(guide).not.toContain("oauthconn:<uuid>");
expect(changelog).toContain("[#40](https://github.com/mohanagy/miftah/issues/40)");
expect(changelog).toContain("Added an owner-readable Miftah 0.5 feature and usage guide");
});

it("keeps every local guide link resolvable", () => {
const links = [...readGuide().matchAll(/\[[^\]]+\]\(([^)]+)\)/gu)].map((match) => match[1]!);

for (const link of links) {
if (/^(?:https?:|mailto:)/u.test(link)) continue;
const path = link.split("#", 1)[0]!;
const target = new URL(path, guideUrl);
expect(existsSync(target), `missing guide link target: ${link}`).toBe(true);
}
Comment thread
coderabbitai[bot] marked this conversation as resolved.
Resolved
});
});
Loading