Pulse
Enables AI agents to investigate and manipulate live network simulations via MCP, including protocol debugging and fault injection.
README
Pulse
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
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 itREADYmake mcp— start the MCP server, then connect your IDE
make labneedssudo(Mininet). Leave it running;Ctrl+Ctears the simulation down cleanly. Without amake labrunning, MCP tools/resources will reportSimulation 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 ofmake test/CI.make labis 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: initialize → notifications/initialized → tools/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:
- Confirm the server is actually running and bound where expected:
Any HTTP response code (evenpulse-mcp & curl -s -o /dev/null -w "%{http_code}\n" http://127.0.0.1:8000/mcp406) confirms the server is listening —curl: (7) Failed to connectmeans the server isn't running or is bound to a different host/port than the client is configured with. - Confirm the full MCP handshake succeeds (this is what a real client
does):
Expectcurl -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"}}}'200 OKwithcontent-type: application/jsonand aserverInfo/capabilitiesJSON-RPC response body. If this fails, the problem is server-side (checkpulse-mcp's own output for a traceback) — this step isolates server bugs from client/config issues. - Confirm the URL in
mcp_config.jsonmatches 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 forcurl -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. - 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. - 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:
- Start with docs/architecture/vision-and-positioning.md
For implementing:
- Start with docs/execution/EXECUTION-WORKSPACE.md
- Then docs/execution/PROJECT-STRUCTURE.md
- Then docs/execution/EXECUTION-PHASES.md
For autonomous coding agents:
- See AGENTS.md (repository onboarding for agents)
For navigating documentation:
- See docs/OVERVIEW.md (engineering handbook index)
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]
推荐服务器
Baidu Map
百度地图核心API现已全面兼容MCP协议,是国内首家兼容MCP协议的地图服务商。
Playwright MCP Server
一个模型上下文协议服务器,它使大型语言模型能够通过结构化的可访问性快照与网页进行交互,而无需视觉模型或屏幕截图。
Magic Component Platform (MCP)
一个由人工智能驱动的工具,可以从自然语言描述生成现代化的用户界面组件,并与流行的集成开发环境(IDE)集成,从而简化用户界面开发流程。
Audiense Insights MCP Server
通过模型上下文协议启用与 Audiense Insights 账户的交互,从而促进营销洞察和受众数据的提取和分析,包括人口统计信息、行为和影响者互动。
VeyraX
一个单一的 MCP 工具,连接你所有喜爱的工具:Gmail、日历以及其他 40 多个工具。
graphlit-mcp-server
模型上下文协议 (MCP) 服务器实现了 MCP 客户端与 Graphlit 服务之间的集成。 除了网络爬取之外,还可以将任何内容(从 Slack 到 Gmail 再到播客订阅源)导入到 Graphlit 项目中,然后从 MCP 客户端检索相关内容。
Kagi MCP Server
一个 MCP 服务器,集成了 Kagi 搜索功能和 Claude AI,使 Claude 能够在回答需要最新信息的问题时执行实时网络搜索。
e2b-mcp-server
使用 MCP 通过 e2b 运行代码。
Neon MCP Server
用于与 Neon 管理 API 和数据库交互的 MCP 服务器
Exa MCP Server
模型上下文协议(MCP)服务器允许像 Claude 这样的 AI 助手使用 Exa AI 搜索 API 进行网络搜索。这种设置允许 AI 模型以安全和受控的方式获取实时的网络信息。