Skip to main content
Glama

Pulse

Python 3.10+ MCP Status

Pulse is a network behavior simulation environment. It creates simulated networks where devices run real Linux networking stacks and routing protocols, enabling investigation of runtime behavior through device interaction and AI agents.

Pulse answers: "What is happening inside the network right now?"

# Terminal 1                      # Terminal 2
make lab                          make mcp

make lab builds and holds a live network simulation open; make mcp starts the MCP server your IDE connects to. See Quick Start.

How It Works

An AI agent (via an MCP-capable IDE like Windsurf) talks to Pulse over MCP. Pulse's backend reads and mutates a live Mininet/FRR simulation — there is no separate model of the network to fall out of sync with; the running simulation is the state.

flowchart LR
    Agent["AI Agent (IDE / Windsurf Cascade)"] -- MCP over HTTP --> MCP["Pulse MCP server (FastMCP)"]
    MCP --> State["state/ (read-only queries)"]
    MCP --> Safety["safety/ (mutations, snapshot, rollback)"]
    State --> Sim[("Live simulation\nMininet namespaces + FRR daemons")]
    Safety --> Sim
    Sim -.->|OSPF, ARP, interfaces,\nrunning-config| State

Related MCP server: @nimbus21.ai/chrome-devtools-mcp

What Pulse Is

  • A simulated network environment using Mininet (Linux namespaces) and FRRouting (OSPF, BGP)

  • Protocol-level investigation (OSPF adjacency, routing tables, VLAN behavior)

  • Runtime fault injection (latency, loss, interface failures)

  • AI agent integration via MCP (Model Context Protocol)

  • Terminal-like device access for human and automated investigation

What Pulse Is Not

  • Not a production network monitoring tool

  • Not a vendor CLI simulator (no Cisco IOS / Juniper JunOS)

  • Not a hardware ASIC emulator

  • Not a large-scale topology modeler

  • Not a telemetry or time-series analysis platform (v1)

  • Not a multi-user collaboration platform (MVP)

Relationship with Graphite

Pulse is a sibling project to Graphite. They are complementary:

  • Graphite: "What does the network look like?" (topology structure, blast-radius analysis)

  • Pulse: "What is happening inside the network right now?" (runtime behavior, protocol debugging)

Current State

Project maturity: Architecture and specification complete, execution planned. Milestones 0–5 (simulation runtime, FRR config, state reads, read-only MCP tools, mutation/safety subsystem) are implemented; Milestone 6 (hardening and expansion) has completed its entire MCP tool-catalog roadmap — every proposed resource/tool is implemented — plus the seven MVP-scope agent Skills (docs/skills/) and four foundational Rules (docs/rules/). Marketplace/IDE connectivity is verified end-to-end. Formal Observability, the Custom Agent Flow, and the frontend are explicitly deferred (ADR 0003) — not open MVP work.

Pulse has completed:

  • Architecture phase (cross-cutting system concerns)

  • Specification phase (implementation contracts for MVP backend)

  • Execution planning phase (build order, module boundaries, process)

  • MCP surface: 9 resources + 16 tools (see docs/specs/mcp-tool-catalog.md)

  • 7 agent Skills, verified connected to Windsurf's Marketplace

See docs/execution/EXECUTION-PHASES.md for current Milestone status and docs/investigations/ for evidence gathered so far.

Quick Start

Prerequisites: Python 3.10+, Mininet + FRR installed as system packages (not pip-installed — see docs/investigations/milestone-0-environment-constraints.md).

make install    # venv --system-site-packages + pip install -e ".[dev]"
make test       # pytest tests/unit

The standard development workflow is two terminals:

Terminal 1

Terminal 2

make lab — build the MVP topology, hold it READY

make mcp — start the MCP server, then connect your IDE

make lab needs sudo (Mininet). Leave it running; Ctrl+C tears the simulation down cleanly. Without a make lab running, MCP tools/resources will report Simulation state: UNINITIALIZED — there's nothing yet for them to read or mutate.

Run make help for the full command list. Without make, the equivalent raw commands are:

python3 -m venv --system-site-packages .venv && . .venv/bin/activate
pip install -e ".[dev]"
pytest tests/unit
sudo .venv/bin/pulse-lab   # terminal 1
pulse-mcp                 # terminal 2

Server startup options

pulse-mcp                                   # http on 127.0.0.1:8000/mcp (default, validated with Windsurf Marketplace)
pulse-mcp --host 0.0.0.0 --port 9000        # override host/port
pulse-mcp --transport stdio                 # for an IDE that spawns Pulse as a subprocess instead
pulse-lab --topology hub-and-spoke-mvp       # override topology (currently the only one)

Mutation approval mode

Mutation tools (fault injection, interface state changes, etc.) require approval before execution. The approval mechanism is controlled by the PULSE_APPROVAL_MODE environment variable:

export PULSE_APPROVAL_MODE=chat   # default: agent asks user in chat before calling tool
export PULSE_APPROVAL_MODE=mcp    # uses FastMCP's elicitation callback (may not work with all clients)
export PULSE_APPROVAL_MODE=none   # no confirmation (automation/testing only)

CHAT (default): The agent asks you for confirmation in the chat interface before calling the mutation tool. The MCP server approves immediately, trusting the agent's chat confirmation. This works across all MCP clients (Windsurf, Cursor, Claude Code, VS Code) and is the recommended default for local development.

MCP: Uses FastMCP's Context.elicit() callback, which sends a blocking request to the connected MCP client. This was confirmed working with FastMCP's in-memory client but may not be supported by all MCP clients. Windsurf Marketplace, for example, does not currently support elicitation.

NONE: No confirmation. Mutations execute immediately. Useful for automation and testing only. Should not be used in production.

Developer Experience

Task

Command

Install

make install

Run unit tests

make test

Build + hold the simulation READY

make lab (sudo)

Start the MCP server (HTTP)

make mcp

Start the MCP server (stdio)

make mcp-stdio

Simulation smoke test (Milestone 0 — build topology, confirm OSPF, teardown)

make smoke-build (sudo)

State/MCP smoke test (Milestone 3/4 — reads + tool registration against a live sim)

make smoke-mcp (sudo)

Mutation smoke test (Milestone 5 — apply + roll back a mutation against a live sim)

make smoke-mutation (sudo)

Clean up leaked Mininet state

make clean-mininet (sudo)

Note: the smoke-* targets are throwaway prototype scripts (prototypes/) — build, assert, teardown once, then exit. They validate a specific question and are not part of make test/CI. make lab is the supported, long-running entrypoint for interactive development; see each smoke script's own module docstring for exactly what it validates.

Connecting an IDE/Marketplace Client (e.g. Windsurf)

Point the client at Pulse's canonical HTTP endpoint. For Windsurf, add this to ~/.codeium/windsurf/mcp_config.json:

{
  "mcpServers": {
    "pulse": {
      "disabled": false,
      "serverUrl": "http://127.0.0.1:8000/mcp"
    }
  }
}

(Windsurf accepts either serverUrl or url for remote HTTP MCP servers — both are equivalent; see Windsurf's MCP docs.)

This has been verified end-to-end against a real Windsurf Marketplace connection: initializenotifications/initializedtools/list, with Marketplace successfully enumerating Pulse's tools. Port 8000 is the validated default — connecting on a different local port was observed to fail Marketplace's connection for reasons not fully understood (see docs/investigations/windsurf-marketplace-connectivity-root-cause.md for the full investigation trail); stick to the default unless you have a specific reason to change it.

Validation checklist — run this in order if the IDE reports it cannot connect, to localize the problem before changing any configuration:

  1. Confirm the server is actually running and bound where expected:

    pulse-mcp &
    curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/mcp

    Any HTTP response code (even 406) confirms the server is listening — curl: (7) Failed to connect means the server isn't running or is bound to a different host/port than the client is configured with.

  2. Confirm the full MCP handshake succeeds (this is what a real client does):

    curl -s -i http://127.0.0.1:8000/mcp \
      -H "Content-Type: application/json" \
      -H "Accept: application/json" \
      -d '{"jsonrpc":"2.0","id":1,"method":"initialize","params":{"protocolVersion":"2024-11-05","capabilities":{},"clientInfo":{"name":"curl","version":"0"}}}'

    Expect 200 OK with content-type: application/json and a serverInfo/ capabilities JSON-RPC response body. If this fails, the problem is server-side (check pulse-mcp's own output for a traceback) — this step isolates server bugs from client/config issues.

  3. Confirm the URL in mcp_config.json matches exactly — scheme, host, port, and path (/mcp, no trailing slash). A trailing-slash mismatch (/mcp/ instead of /mcp) will 307-redirect (standard Starlette behavior for a path that doesn't exactly match a registered route) — harmless for curl -L, but some HTTP client libraries do not resend a streaming POST body across a redirect. Use the exact canonical URL to avoid this entirely rather than relying on redirect-following.

  4. Restart the IDE's MCP connection after editing mcp_config.json — most MCP-capable IDEs (including Windsurf) only re-read this file on an explicit reconnect/reload, not automatically on save.

  5. If still failing, capture the IDE's own MCP error message/log (not just "failed to connect") — steps 1–2 above confirm the server is spec-compliant and reachable, so a remaining failure at this point is in the client's own request construction or config schema for that specific IDE, not in Pulse.

Activating Windsurf Skills and Rules

The .windsurf/ directory is IDE-specific and is not committed to this repo. To use the canonical skills and rules after cloning, copy or symlink them into Windsurf's expected locations:

# Rules are copied as-is
mkdir -p .windsurf/rules
cp docs/rules/*.md .windsurf/rules/

# Skills need a subdirectory per skill and a SKILL.md filename
for skill in docs/skills/*.md; do
  name=$(basename "$skill" .md)
  mkdir -p ".windsurf/skills/$name"
  cp "$skill" ".windsurf/skills/$name/SKILL.md"
done

Windsurf SKILL.md files require a YAML frontmatter block with name and description at the top. If your copy of docs/skills/<name>.md does not include one, prepend it before using it in Windsurf:

---
name: <skill-name>
description: <short description>
---

The docs/skills/ and docs/rules/ files are the source-of-truth authoring versions; .windsurf/ is a local activation copy.

Repository Structure

pulse/
├── docs/
│   ├── architecture/           # Cross-cutting system concerns
│   ├── specs/                  # Implementation specifications
│   ├── execution/              # Build order, module boundaries, process
│   ├── decisions/              # ADRs (Architecture Decision Records)
│   ├── topologies/             # Network topology specifications
│   ├── skills/                 # Agent Skills — authoring/spec layer
│   ├── rules/                  # Foundational agent rules — authoring/spec layer
│   ├── investigations/         # Evidence-gathering writeups (real bugs found, real findings)
│   └── meta/                   # Documentation system, glossary, templates
├── src/backend/                # Implementation — see docs/execution/PROJECT-STRUCTURE.md
│   ├── simulation/             # Mininet/FRR runtime, topology loading, run_lab.py (dev entrypoint)
│   ├── frr/                    # FRR config templates and rendering
│   ├── state/                  # Read-only live-state queries
│   ├── safety/                 # Mutations, snapshot/rollback (sole writer of live state)
│   └── mcp/                    # FastMCP server, resources, tools
├── tests/unit/                 # pytest suite (mirrors src/backend/ layout)
├── prototypes/                 # Throwaway feasibility/smoke-test scripts (never imported by src/)
├── Makefile                    # `make help` for all common commands
├── pyproject.toml              # Dependencies, `pulse-mcp` + `pulse-lab` console scripts
└── README.md                   # This file

Module relationships

flowchart TD
    mcp["mcp/ — FastMCP server, resources, tools, approval gate"]
    state["state/ — read-only live-state queries"]
    safety["safety/ — mutations, snapshot, rollback (sole writer of live state)"]
    frr["frr/ — FRR config templates and rendering"]
    simulation["simulation/ — Mininet/FRR runtime, topology loading"]

    mcp --> state
    mcp --> safety
    safety --> simulation
    state --> simulation
    safety --> frr
    frr --> simulation

See docs/execution/MODULE-BOUNDARIES.md for the authoritative description of what each module owns and may not reach across.

Where to Start

For understanding Pulse:

For implementing:

For autonomous coding agents:

  • See AGENTS.md (repository onboarding for agents)

For navigating documentation:

Technology Stack

  • Simulation: Mininet (Linux network namespaces)

  • Routing: FRRouting (OSPF, BGP)

  • Backend: Python, FastMCP (FastAPI was considered and not adopted — FastMCP's own native HTTP transport covers Pulse's needs; see docs/architecture/technology-decisions.md)

  • Agent Orchestration: IDE Flow only for MVP — the IDE's own agent runtime, no Pulse-side orchestrator (ADR 0003). LangChain is a Working Assumption for the Custom Agent Flow only, which is deferred; see docs/architecture/technology-decisions.md.

  • Frontend: Deferred for MVP (see ADR 0003)

Documentation System

Pulse uses a structured documentation system defined in docs/meta/DOCUMENTATION-SYSTEM.md. All documents follow maturity labeling (Established, Working Assumption, Exploration, Deferred, Superseded, Rejected) and carry explicit metadata.

Decision Records

Significant architectural decisions are recorded as ADRs in docs/decisions/:

  • 0001: Pulse owns the simulation lifecycle; one active simulation for MVP

  • 0002: The live simulation is the source of truth; config is seed

  • 0003: Defer the Custom Agent Flow; MVP is IDE-Flow-only

  • 0004: Two approval levels for MVP (read-only vs. mutation)

  • 0005: MVP OSPF scope: single-area, adjacency + propagation only

  • 0006: Local Unix-socket RPC boundary between the Runtime (make lab) and MCP (make mcp) processes

MVP Scope

Topology: Hub-and-spoke with 3 switches (Access-SW1, Access-SW2, Core-L3-SW) and 3 endpoints (Host-A, Host-B, Server)

Protocols: VLAN tagging, trunking, SVI, basic routing (static and simple OSPF), ARP, ICMP

Agent Flow: IDE Flow only (Windsurf IDE agent via MCP). Custom Agent Flow deferred.

License

[To be determined]

F
license - not found
-
quality - not tested
B
maintenance

Maintenance

Maintainers
Response time
Release cycle
Releases (12mo)
Commit activity

Resources

Unclaimed servers have limited discoverability.

Looking for Admin?

If you are the server author, to access and configure the admin panel.

Latest Blog Posts

MCP directory API

We provide all the information about MCP servers via our MCP API.

curl -X GET 'https://glama.ai/api/mcp/v1/servers/SudarshanKomar/pulse'

If you have feedback or need assistance with the MCP directory API, please join our Discord server