npm package discovery and stats viewer.

Discover Tips

  • General search

    [free text search, go nuts!]

  • Package details

    pkg:[package-name]

  • User packages

    @[username]

Sponsor

Optimize Toolset

I’ve always been into building performant and accessible sites, but lately I’ve been taking it extremely seriously. So much so that I’ve been building a tool to help me optimize and monitor the sites that I build to make sure that I’m making an attempt to offer the best experience to those who visit them. If you’re into performant, accessible and SEO friendly sites, you might like it too! You can check it out at Optimize Toolset.

About

Hi, 👋, I’m Ryan Hefner  and I built this site for me, and you! The goal of this site was to provide an easy way for me to check the stats on my npm packages, both for prioritizing issues and updates, and to give me a little kick in the pants to keep up on stuff.

As I was building it, I realized that I was actually using the tool to build the tool, and figured I might as well put this out there and hopefully others will find it to be a fast and useful way to search and browse npm packages as I have.

If you’re interested in other things I’m working on, follow me on Twitter or check out the open source projects I’ve been publishing on GitHub.

I am also working on a Twitter bot for this site to tweet the most popular, newest, random packages from npm. Please follow that account now and it will start sending out packages soon–ish.

Open Software & Tools

This site wouldn’t be possible without the immense generosity and tireless efforts from the people who make contributions to the world and share their work via open source initiatives. Thank you 🙏

© 2026 – Pkg Stats / Ryan Hefner

macp-sdk-typescript

v0.3.0

Published

TypeScript SDK for the MACP Rust runtime

Readme

macp-sdk-typescript

TypeScript SDK for the Multi-Agent Coordination Protocol (MACP) runtime. Connects TypeScript/Node.js applications to the Rust MACP runtime over gRPC.

Install

npm install macp-sdk-typescript

The SDK depends on @multiagentcoordinationprotocol/proto from GitHub Packages. Create a .npmrc in your project root:

@multiagentcoordinationprotocol:registry=https://npm.pkg.github.com

And configure a GitHub PAT with read:packages scope:

npm config set //npm.pkg.github.com/:_authToken YOUR_GITHUB_PAT

Quick Start

import { Auth, MacpClient, DecisionSession } from 'macp-sdk-typescript';

const client = new MacpClient({
  address: '127.0.0.1:50051',
  secure: false,
  allowInsecure: true, // local dev only; production must use TLS
  auth: Auth.devAgent('coordinator'),
});

await client.initialize();

const session = new DecisionSession(client);
await session.start({
  intent: 'pick a deployment strategy',
  participants: ['alice', 'bob'],
  ttlMs: 60_000,
});

await session.propose({ proposalId: 'p1', option: 'canary', rationale: 'low risk' });

await session.vote({
  proposalId: 'p1',
  vote: 'approve',
  sender: 'alice',
  auth: Auth.devAgent('alice'),
});

const winner = session.projection.majorityWinner();
await session.commit({
  action: 'deployment.approved',
  authorityScope: 'release',
  reason: `winner=${winner}`,
});

client.close();

Architecture

The SDK uses a two-layer design:

  • Low-level transport (MacpClient): gRPC connection to the runtime with all 14 RPCs — initialize, send, openStream, getSession, cancelSession, getManifest, listModes, listRoots, listExtModes, registerExtMode, unregisterExtMode, promoteMode, plus streaming watchers.
  • High-level session helpers: One class per coordination mode (DecisionSession, ProposalSession, TaskSession, HandoffSession, QuorumSession). Each wraps MacpClient, builds envelopes, encodes payloads, and maintains a local state projection.

Every session class follows the same pattern:

  1. Construct with a MacpClient and options
  2. Call start() to initiate the session
  3. Call mode-specific methods (propose, vote, accept, etc.)
  4. Call commit() to finalize
  5. Read session.projection for local state

Session Start Options

All start() methods accept contextId and extensions for session-level metadata:

await session.start({
  intent: 'pick a deployment strategy',
  participants: ['alice', 'bob'],
  ttlMs: 60_000,
  contextId: 'ctx-abc',                           // optional opaque context reference
  extensions: { 'x-trace': Buffer.from('tid') },  // optional typed extension buffers
  roots: [{ uri: 'file:///workspace', name: 'repo' }],
});

Coordination Modes

Decision Mode

Structured decision with proposals, evaluations, objections, and votes.

import { DecisionSession } from 'macp-sdk-typescript';

const session = new DecisionSession(client);
await session.start({ intent: '...', participants: ['alice'], ttlMs: 60_000 });
await session.propose({ proposalId: 'p1', option: 'A', rationale: '...' });
await session.evaluate({ proposalId: 'p1', recommendation: 'approve', confidence: 0.9 });
await session.raiseObjection({ proposalId: 'p1', reason: 'risk', severity: 'high' });
await session.vote({ proposalId: 'p1', vote: 'approve' });
await session.commit({ action: 'decided', authorityScope: 'team', reason: '...' });

// Projection queries
session.projection.voteTotals();                 // { p1: 1 }
session.projection.majorityWinner();             // 'p1'
session.projection.hasBlockingObjection('p1');   // true (severity: high)

Proposal Mode

Proposal and counterproposal negotiation.

import { ProposalSession } from 'macp-sdk-typescript';

const session = new ProposalSession(client);
await session.start({ intent: '...', participants: ['bob'], ttlMs: 60_000 });
await session.propose({ proposalId: 'p1', title: 'Plan A', summary: '...' });
await session.counterPropose({ proposalId: 'p2', supersedesProposalId: 'p1', title: 'Plan B' });
await session.accept({ proposalId: 'p2', reason: 'better' });
await session.commit({ action: 'proposal.accepted', authorityScope: 'team', reason: '...' });

// Projection queries
session.projection.activeProposals();            // proposals with status 'open'
session.projection.isAccepted('p2');             // true
session.projection.isTerminallyRejected('p1');   // false

Task Mode

Bounded task delegation.

import { TaskSession } from 'macp-sdk-typescript';

const session = new TaskSession(client);
await session.start({ intent: '...', participants: ['worker'], ttlMs: 120_000 });
await session.requestTask({ taskId: 't1', title: 'Build feature', instructions: '...' });
await session.acceptTask({ taskId: 't1', assignee: 'worker' });
await session.updateTask({ taskId: 't1', status: 'working', progress: 0.5, message: 'halfway' });
await session.completeTask({ taskId: 't1', assignee: 'worker', summary: 'done' });
await session.commit({ action: 'task.completed', authorityScope: 'lead', reason: '...' });

// Projection queries
session.projection.progressOf('t1');   // 1.0
session.projection.isComplete('t1');   // true
session.projection.activeTasks();      // []

Handoff Mode

Responsibility transfer between participants.

import { HandoffSession } from 'macp-sdk-typescript';

const session = new HandoffSession(client);
await session.start({ intent: '...', participants: ['bob'], ttlMs: 60_000 });
await session.offer({ handoffId: 'h1', targetParticipant: 'bob', scope: 'frontend' });
await session.addContext({ handoffId: 'h1', contentType: 'application/json', context: buf });
await session.acceptHandoff({ handoffId: 'h1', acceptedBy: 'bob' });
await session.commit({ action: 'handoff.accepted', authorityScope: 'team', reason: '...' });

// Projection queries
session.projection.isAccepted('h1');      // true
session.projection.pendingHandoffs();     // []

Quorum Mode

Threshold-based approval voting.

import { QuorumSession } from 'macp-sdk-typescript';

const session = new QuorumSession(client);
await session.start({ intent: '...', participants: ['alice', 'bob', 'carol'], ttlMs: 60_000 });
await session.requestApproval({ requestId: 'r1', action: 'deploy', summary: '...', requiredApprovals: 2 });
await session.approve({ requestId: 'r1', reason: 'ok' });
await session.commit({ action: 'quorum.approved', authorityScope: 'ops', reason: '...' });

// Projection queries
session.projection.hasQuorum('r1');              // true/false
session.projection.approvalCount('r1');          // number
session.projection.remainingVotesNeeded('r1');   // number
session.projection.votedSenders('r1');           // string[]

Agent Framework

The agent module provides event-driven abstractions for building MACP participants.

Participant

Participant wraps a session, projection, and transport into a single event-driven handler:

import { agent } from 'macp-sdk-typescript';

const participant = new agent.Participant({
  participantId: 'evaluator',
  sessionId: 'sid-123',
  mode: 'macp.mode.decision.v1',
  client,
  transport: new agent.GrpcTransportAdapter(client, 'sid-123', auth),
});

participant
  .on('Proposal', async (msg, ctx) => {
    await ctx.actions.evaluate({
      proposalId: msg.payload.proposalId,
      recommendation: 'APPROVE',
      confidence: 0.95,
    });
  })
  .onTerminal(async (result) => {
    console.log('session ended:', result.reason);
  });

await participant.run();

Bootstrap Runner

fromBootstrap() creates a fully-wired Participant from a JSON bootstrap file (typically provided by the runtime orchestrator):

import { agent } from 'macp-sdk-typescript';

// Reads from path argument or MACP_BOOTSTRAP_FILE env var
const participant = agent.fromBootstrap('./bootstrap.json');
participant.on('Proposal', handler);
await participant.run();

Bootstrap files can include an initiator section for participants that start the session:

{
  "session_id": "sid-123",
  "participant_id": "coordinator",
  "mode": "macp.mode.decision.v1",
  "runtime_address": "localhost:50051",
  "initiator": {
    "session_start": {
      "intent": "pick deployment strategy",
      "participants": ["coordinator", "evaluator"],
      "ttl_ms": 60000,
      "roots": [{ "uri": "file:///workspace" }]
    },
    "kickoff": {
      "message_type": "Proposal",
      "payload": { "proposalId": "p1", "option": "canary" }
    }
  }
}

Authentication

// Development (uses x-macp-agent-id header)
const auth = Auth.devAgent('my-agent');

// Production (Bearer token with authenticated identity — RFC-MACP-0004 §4).
// The SDK refuses to emit an envelope whose `sender` differs from
// `expectedSender`, so bugs surface locally instead of as runtime NACKs.
const auth = Auth.bearer('token-value', { expectedSender: 'alice' });

// Legacy form — bearer with only a sender hint, no identity guard:
const loose = Auth.bearer('token-value', 'alice');

Pass auth to the client constructor for default auth, or per-method for multi-agent scenarios:

await session.vote({
  proposalId: 'p1',
  vote: 'approve',
  sender: 'alice',
  auth: Auth.devAgent('alice'),
});

TLS

TLS is on by default (RFC-MACP-0006 §3). To connect to an insecure runtime during local development, you must opt out explicitly:

const client = new MacpClient({
  address: '127.0.0.1:50051',
  secure: false,
  allowInsecure: true, // must be paired with secure: false
  auth,
});

Omit allowInsecure in production — the constructor throws when secure: false is passed without it.

Streaming

Session Streaming

const stream = client.openStream({ auth });
await stream.send(envelope);

for await (const envelope of stream.responses()) {
  console.log(envelope.messageType, envelope.sender);
}

stream.close();

To attach to a session that is already in flight and receive accepted history before live broadcast (RFC-MACP-0006 §3.2 passive subscribe):

const stream = client.openStream({ auth });
await stream.sendSubscribe(sessionId);            // full replay then live
// or, after a reconnect:
await stream.sendSubscribe(sessionId, lastSeq);    // resume from cursor

The agent framework's GrpcTransportAdapter calls this for you on start, so non-initiator agents see SessionStart regardless of join order.

Registry & Root Watchers

import { ModeRegistryWatcher, RootsWatcher } from 'macp-sdk-typescript';

const watcher = new ModeRegistryWatcher(client, { auth });

// Async iterator with abort support
const controller = new AbortController();
for await (const change of watcher.changes(controller.signal)) {
  console.log('registry changed at', change.observedAtUnixMs);
}

// Or one-shot
const next = await watcher.nextChange();

Error Handling

import { MacpAckError, MacpTransportError } from 'macp-sdk-typescript';

try {
  await session.vote({ proposalId: 'p1', vote: 'approve' });
} catch (err) {
  if (err instanceof MacpAckError) {
    console.log(err.ack.error?.code); // 'SESSION_NOT_OPEN', etc.
  } else if (err instanceof MacpTransportError) {
    console.log('gRPC connectivity issue');
  }
}

Development

npm run build              # Compile TypeScript
npm run check              # Type-check only
npm run lint               # ESLint
npm run format             # Prettier
npm test                   # Run unit + conformance tests
npm run test:watch         # Watch mode
npm run test:coverage      # With coverage
npm run test:integration   # Integration tests (requires Docker runtime)

Integration Tests

Run the full SDK against a live MACP runtime:

# Build and start the runtime
docker build -t macp-runtime ../runtime/
docker run -d --name macp-runtime-test -p 50051:50051 \
  -e MACP_BIND_ADDR=0.0.0.0:50051 -e MACP_ALLOW_INSECURE=1 \
  -e MACP_ALLOW_DEV_SENDER_HEADER=1 -e MACP_MEMORY_ONLY=1 macp-runtime

# Run tests
npm run test:integration

# Clean up
docker rm -f macp-runtime-test

Runtime Boundary

This SDK is a client for the MACP Rust runtime. The runtime handles session state, message ordering, deduplication, TTL enforcement, and mode-specific validation. The SDK provides typed helpers for building and sending envelopes, and local projections for tracking state client-side.

License

Apache-2.0