diff --git a/rocolib/__main__.py b/rocolib/__main__.py
index 16d782d08641a9bc48007dd95da2d2e27e8c290b..8f5f071bd8a522a9f95cf9e41092de01235c92f2 100644
--- a/rocolib/__main__.py
+++ b/rocolib/__main__.py
@@ -1,8 +1,10 @@
 #!/bin/env python
 
+import sys
 import logging
 import argparse
-from rocolib.library import getComponent
+from pprint import pprint
+from rocolib.library import getComponent, getComponentTree
 from rocolib.api.composables.graph.Joint import FingerJoint
 
 
@@ -26,15 +28,30 @@ if __name__ == '__main__':
     DEFAULT_LOG_LEVEL = "WARNING"
 
     parser = argparse.ArgumentParser()
-    parser.add_argument("component", help="Name of the component you'd like to test")
-    parser.add_argument("--verbose", "-v", dest="log_level", action="append_const", const=-1)
-    parser.add_argument("--quiet", "-q", dest="log_level", action="append_const", const=1)
-    parser.add_argument("-t", type=float, help="Thickness if you are making with wood")
+
+    cmd = parser.add_mutually_exclusive_group(required=True)
+    cmd.add_argument("component", nargs='?',
+                    help="Name of the component you'd like to test (cannot be used with --list/-l)")
+    cmd.add_argument("--list", "-l", action='store_true',
+                    help="List all known library components (cannot be used with component)")
+
+    parser.add_argument("--verbose", "-v", help="Increase logging level (can be used multiple times)",
+                        dest="log_level", action="append_const", const=-1)
+    parser.add_argument("--quiet", "-q", help="Decrease logging level (can be used multiple times)",
+                        dest="log_level", action="append_const", const=1)
+    parser.add_argument("-P", help="List component parameters (use multiple times for more detail)",
+                        dest="param_list", action="append_const", const=1)
+    parser.add_argument("-t", type=float, help="Thickness (i.e. making with wood)")
     parser.add_argument("-d", action='store_true', help="Display 2D drawing")
     parser.add_argument("-D", action='store_true', help="Display 3D drawing")
-    parser.add_argument("-P", nargs=2, action='append',
+    parser.add_argument("-p", nargs=2, action='append',
         metavar=("NAME", "VALUE"),
         help="Set component parameter NAME to value VALUE")
+
+    if len(sys.argv)==1:
+        parser.print_help(sys.stderr)
+        sys.exit(1)
+
     args = parser.parse_args()
 
     log_level = LOG_LEVELS.index(DEFAULT_LOG_LEVEL)
@@ -45,4 +62,24 @@ if __name__ == '__main__':
     log_level_name = LOG_LEVELS[log_level]
     logging.basicConfig(level=getattr(logging, log_level_name))
 
-    test(args.component, args.P, thickness=args.t, display=args.d, display3D=args.D)
+    if args.component:
+        if args.param_list:
+            f = getComponent(args.component)
+            info = f.getParameterInfo()
+            if len(args.param_list) == 1:
+                print("\n".join(info.keys()))
+            elif len(args.param_list) == 2:
+                pprint({k: v['defaultValue'] for k,v in info.items()})
+            elif len(args.param_list) == 3:
+                pprint({k: {x: v[x] for x in ('defaultValue', 'spec')} for k,v in info.items()})
+            else:
+                pprint(info)
+
+            if not args.p or args.t or args.d or args.D:
+                exit(0)
+        test(args.component, args.p, thickness=args.t, display=args.d, display3D=args.D)
+    elif args.list:
+        t = getComponentTree()
+        for i, cs in enumerate(t):
+            chunks = [cs[x:x+4] for x in range(0, len(cs), 4)]
+            print(f"{i:2}: " + "\n    ".join((" ".join(x) for x in chunks)))