gp

module
v0.2.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Feb 10, 2026 License: MIT

README

gp

CI Go Reference

PDDL planning solver exposed as an MCP server and Go library.

gp implements the Graphplan algorithm (Blum & Furst 1997) for STRIPS planning domains with typing and equality. It ships as:

  • gp-server -- an MCP server that any AI assistant can call
  • graphplan -- a Go library for embedding planning in your apps
  • pddl -- a PDDL parser that feeds into the solver

Background

What is automated planning?

Automated planning finds a sequence of actions that transforms an initial state into a goal state. You describe what you want -- not how to get there.

A planning problem has three parts:

  • Domain -- the types of objects and actions available
  • Problem -- the specific objects, starting state, and goal
  • Plan -- the output: a sequence of grounded actions
PDDL: Planning Domain Definition Language

PDDL is the standard input format for planners. A domain defines predicates (facts about the world) and operators (actions with preconditions and effects):

(define (domain logistics)
  (:requirements :strips :typing)
  (:types city cargo rocket)
  (:predicates (at ?x - cargo ?c - city)
               (in ?x - cargo ?r - rocket)
               (rocket-at ?r - rocket ?c - city)
               (has-fuel ?r - rocket))
  (:action load
    :parameters (?c - cargo ?r - rocket ?loc - city)
    :precondition (and (at ?c ?loc) (rocket-at ?r ?loc))
    :effect (and (not (at ?c ?loc)) (in ?c ?r)))
  ;; ... more actions
)

A problem specifies objects, initial facts, and goals:

(define (problem deliver)
  (:domain logistics)
  (:objects r1 - rocket  a b - cargo
            london paris - city)
  (:init (at a london) (at b london)
         (rocket-at r1 london) (has-fuel r1))
  (:goal (and (at a paris) (at b paris))))
The Graphplan algorithm

Graphplan (Blum & Furst 1997) builds a layered planning graph alternating between proposition levels and action levels. At each level it tracks mutual exclusion (mutex) constraints -- pairs of actions or propositions that cannot coexist.

The algorithm:

  1. Extend the graph one level (add applicable actions, compute new mutexes)
  2. Check if all goals are present and pairwise non-mutex
  3. Search backward through the graph for a valid plan
  4. Repeat until a plan is found or the graph levels off with no solution

Key properties:

  • Finds shortest parallel plans (fewest time steps)
  • Guaranteed complete -- if a plan exists, it will find it
  • Memoization prunes the search space across iterations

Examples

Rocket cargo transport

A rocket must transport two pieces of cargo from London to Paris.

domain.pddl
(define (domain rocket)
  (:requirements :strips :typing :equality)
  (:types rocket place cargo - object)
  (:predicates
    (at ?x - object ?y - place)
    (in ?c - cargo ?r - rocket)
    (has-fuel ?r - rocket))
  (:action move
    :parameters (?r - rocket ?from - place ?to - place)
    :precondition (and
      (not (= ?from ?to))
      (at ?r ?from)
      (has-fuel ?r))
    :effect (and
      (at ?r ?to)
      (not (at ?r ?from))
      (not (has-fuel ?r))))
  (:action load
    :parameters (?r - rocket ?p - place ?c - cargo)
    :precondition (and (at ?r ?p) (at ?c ?p))
    :effect (and
      (in ?c ?r)
      (not (at ?c ?p))))
  (:action unload
    :parameters (?r - rocket ?p - place ?c - cargo)
    :precondition (and (at ?r ?p) (in ?c ?r))
    :effect (and
      (at ?c ?p)
      (not (in ?c ?r)))))
problem.pddl
(define (problem rocket-2cargo)
  (:domain rocket)
  (:objects
    r1 - rocket
    london paris - place
    a b - cargo)
  (:init
    (at r1 london)
    (at a london)
    (at b london)
    (has-fuel r1))
  (:goal (and
    (at a paris)
    (at b paris))))

Plan (3 time steps):

Step 0: load(r1, london, a)  load(r1, london, b)
Step 1: move(r1, london, paris)
Step 2: unload(r1, paris, a)  unload(r1, paris, b)

Both cargo items load in parallel, the rocket moves, and both unload in parallel -- the shortest possible plan.

Blocks world (Sussman anomaly)

The classic AI planning benchmark. Three blocks must be stacked in order, but the initial configuration forces the planner to undo partial progress.

domain.pddl
(define (domain blocks-world)
  (:requirements :strips :typing)
  (:types block - object)
  (:predicates
    (on ?x - block ?y - block)
    (on-table ?x - block)
    (clear ?x - block)
    (holding ?x - block)
    (arm-empty))
  (:action pick-up
    :parameters (?x - block)
    :precondition (and
      (clear ?x)
      (on-table ?x)
      (arm-empty))
    :effect (and
      (holding ?x)
      (not (on-table ?x))
      (not (clear ?x))
      (not (arm-empty))))
  (:action put-down
    :parameters (?x - block)
    :precondition (holding ?x)
    :effect (and
      (on-table ?x)
      (clear ?x)
      (arm-empty)
      (not (holding ?x))))
  (:action stack
    :parameters (?x - block ?y - block)
    :precondition (and
      (holding ?x)
      (clear ?y))
    :effect (and
      (on ?x ?y)
      (clear ?x)
      (arm-empty)
      (not (holding ?x))
      (not (clear ?y))))
  (:action unstack
    :parameters (?x - block ?y - block)
    :precondition (and
      (on ?x ?y)
      (clear ?x)
      (arm-empty))
    :effect (and
      (holding ?x)
      (clear ?y)
      (not (on ?x ?y))
      (not (clear ?x))
      (not (arm-empty)))))
problem.pddl (Sussman anomaly)
(define (problem sussman-anomaly)
  (:domain blocks-world)
  (:objects a b c - block)
  (:init
    (on c a)
    (on-table a)
    (on-table b)
    (clear c)
    (clear b)
    (arm-empty))
  (:goal (and
    (on a b)
    (on b c))))

Initial state: C is on A, A and B are on the table. Goal: A on B, B on C (stack: A-B-C from top to bottom).

This is the Sussman anomaly -- you cannot achieve both subgoals independently without undoing one. The planner must unstack C from A before building the target stack.

Installation

Download the latest release for your platform:

Linux / macOS:

curl -sSL https://raw.githubusercontent.com/byte4ever/gp/master/install.sh | sh

Windows (PowerShell):

irm https://raw.githubusercontent.com/byte4ever/gp/master/install.ps1 | iex

Verify:

gp-server --version
Build from source
go install github.com/byte4ever/gp/cmd/gp-server@latest

Requires Go 1.25+.

MCP Configuration

Claude Desktop

Add to claude_desktop_config.json:

{
  "mcpServers": {
    "gp": {
      "command": "gp-server"
    }
  }
}
Claude Code

Add to your project's .mcp.json:

{
  "mcpServers": {
    "gp": {
      "command": "gp-server",
      "type": "stdio"
    }
  }
}

Or run directly:

claude mcp add gp gp-server
Other MCP clients

gp-server speaks MCP over stdio. Point any MCP-compatible client at the gp-server binary with no arguments.

MCP Tools

One-shot solving
Tool Parameters Description
solve_problem format (pddl or json), domain, problem Parse and solve a planning problem in a single call.
Session-based solving

For multi-turn workflows where the AI assistant builds up the domain and problem incrementally:

Tool Parameters Description
create_session name Create a named planning session.
set_domain session, domain Set the PDDL domain on a session.
set_problem session, problem Set the PDDL problem on a session.
solve_session session Solve the problem stored in a session.
list_sessions -- List all active session names.
delete_session session Delete a session by name.
Response format

All solve tools return a list of time steps. Actions within the same step are guaranteed non-interfering and can be executed in parallel. Steps must be executed sequentially:

{
  "solvable": true,
  "steps": [
    {"time": 0, "actions": ["load(r1, london, a)", "load(r1, london, b)"]},
    {"time": 1, "actions": ["move(r1, london, paris)"]},
    {"time": 2, "actions": ["unload(r1, paris, a)", "unload(r1, paris, b)"]}
  ]
}

When no plan exists:

{
  "solvable": false,
  "error": "no valid plan found"
}

Go Library

Three packages, each usable independently:

go get github.com/byte4ever/gp
graphplan -- solver engine
import "github.com/byte4ever/gp/graphplan"

Build domain and problem structs programmatically, then solve:

solver, err := graphplan.NewSolver(nil)
plan, err := solver.Solve(problem)

See graphplan/README.md for full API.

pddl -- parser
import "github.com/byte4ever/gp/pddl"

Parse PDDL strings into graphplan types:

adapter := pddl.NewAdapter()
domain, err := adapter.ParseDomain(domainPDDL)
problem, err := adapter.ParseProblem(problemPDDL, domain)

Supports :strips, :typing, and :equality requirements. See pddl/README.md for full API.

mcpserver -- MCP transport
import "github.com/byte4ever/gp/mcpserver"

Embed the MCP server in your own application:

srv, err := mcpserver.NewServer(cfg, solver, adapter, adapter)
srv.Run()

See mcpserver/README.md for full API.

Project Structure

cmd/gp-server/      Entrypoint binary
graphplan/           Solver engine (Graphplan algorithm)
pddl/                PDDL parser and AST-to-graphplan converter
mcpserver/           MCP server wiring and tool handlers
testdata/            PDDL test fixtures
install.sh           Linux/macOS installer
install.ps1          Windows installer
.goreleaser.yaml     Cross-platform release config

License

MIT

Directories

Path Synopsis
cmd
gp-server command
Command gp-server runs the Graphplan MCP server over stdio.
Command gp-server runs the Graphplan MCP server over stdio.
Package graphplan implements the Graphplan algorithm for solving STRIPS planning problems.
Package graphplan implements the Graphplan algorithm for solving STRIPS planning problems.
examples/rocket command
Command rocket demonstrates solving the rocket transport problem using the graphplan package.
Command rocket demonstrates solving the rocket transport problem using the graphplan package.
Package mcpserver exposes the Graphplan planner as an MCP server.
Package mcpserver exposes the Graphplan planner as an MCP server.
Package pddl provides a parser for PDDL (Planning Domain Definition Language) files.
Package pddl provides a parser for PDDL (Planning Domain Definition Language) files.
examples/parse_rocket command
Command parse_rocket parses the rocket PDDL files and prints the resulting domain and problem.
Command parse_rocket parses the rocket PDDL files and prints the resulting domain and problem.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL