feat: mcpctl v0.0.1 — first public release
Some checks are pending
CI / lint (push) Waiting to run
CI / typecheck (push) Waiting to run
CI / test (push) Waiting to run
CI / build (push) Blocked by required conditions
CI / package (push) Blocked by required conditions

Comprehensive MCP server management with kubectl-style CLI.

Key features in this release:
- Declarative YAML apply/get round-trip with project cloning support
- Gated sessions with prompt intelligence for Claude
- Interactive MCP console with traffic inspector
- Persistent STDIO connections for containerized servers
- RBAC with name-scoped bindings
- Shell completions (fish + bash) auto-generated
- Rate-limit retry with exponential backoff in apply
- Project-scoped prompt management
- Credential scrubbing from git history

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
Michal
2026-02-27 17:05:05 +00:00
parent 414a8d3774
commit 69867bd47a
65 changed files with 5710 additions and 695 deletions

View File

@@ -41,27 +41,28 @@ describe('get command', () => {
expect(deps.fetchResource).toHaveBeenCalledWith('servers', 'srv-1', undefined);
});
it('outputs apply-compatible JSON format', async () => {
it('outputs apply-compatible JSON format (multi-doc)', async () => {
const deps = makeDeps([{ id: 'srv-1', name: 'slack', createdAt: '2025-01-01', updatedAt: '2025-01-01', version: 1 }]);
const cmd = createGetCommand(deps);
await cmd.parseAsync(['node', 'test', 'servers', '-o', 'json']);
const parsed = JSON.parse(deps.output[0] ?? '');
// Wrapped in resource key, internal fields stripped
expect(parsed).toHaveProperty('servers');
expect(parsed.servers[0].name).toBe('slack');
expect(parsed.servers[0]).not.toHaveProperty('id');
expect(parsed.servers[0]).not.toHaveProperty('createdAt');
expect(parsed.servers[0]).not.toHaveProperty('updatedAt');
expect(parsed.servers[0]).not.toHaveProperty('version');
// Array of documents with kind field, internal fields stripped
expect(Array.isArray(parsed)).toBe(true);
expect(parsed[0].kind).toBe('server');
expect(parsed[0].name).toBe('slack');
expect(parsed[0]).not.toHaveProperty('id');
expect(parsed[0]).not.toHaveProperty('createdAt');
expect(parsed[0]).not.toHaveProperty('updatedAt');
expect(parsed[0]).not.toHaveProperty('version');
});
it('outputs apply-compatible YAML format', async () => {
it('outputs apply-compatible YAML format (multi-doc)', async () => {
const deps = makeDeps([{ id: 'srv-1', name: 'slack', createdAt: '2025-01-01' }]);
const cmd = createGetCommand(deps);
await cmd.parseAsync(['node', 'test', 'servers', '-o', 'yaml']);
const text = deps.output[0];
expect(text).toContain('servers:');
expect(text).toContain('kind: server');
expect(text).toContain('name: slack');
expect(text).not.toContain('id:');
expect(text).not.toContain('createdAt:');