diff --git a/Content.Server/Content.Server.csproj b/Content.Server/Content.Server.csproj
index 07b85bcc33..d2cdb12b80 100644
--- a/Content.Server/Content.Server.csproj
+++ b/Content.Server/Content.Server.csproj
@@ -56,6 +56,12 @@
+
+
+
+
+
+
diff --git a/Content.Server/GameObjects/Components/Items/HandsComponent.cs b/Content.Server/GameObjects/Components/Items/HandsComponent.cs
new file mode 100644
index 0000000000..0dc7a00e86
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Items/HandsComponent.cs
@@ -0,0 +1,11 @@
+using SS14.Shared.GameObjects;
+using SS14.Shared.Interfaces.GameObjects;
+using System.Collections.Generic;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public class HandsComponent : Component, IHandsComponent
+ {
+ public override string Name => "Hands";
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Items/InventoryComponent.cs b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs
new file mode 100644
index 0000000000..2374532b95
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Items/InventoryComponent.cs
@@ -0,0 +1,105 @@
+using Content.Server.Interfaces.GameObjects;
+using SS14.Server.GameObjects;
+using SS14.Server.Interfaces.GameObjects;
+using SS14.Shared.GameObjects;
+using SS14.Shared.Interfaces.GameObjects;
+using System;
+using System.Collections.Generic;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public class InventoryComponent : Component, IInventoryComponent
+ {
+ public override string Name => "Inventory";
+
+ private Dictionary slots = new Dictionary();
+ private TransformComponent transform;
+ // TODO: Make this container unique per-slot.
+ private IContainer container;
+
+ public override void Initialize()
+ {
+ transform = Owner.GetComponent();
+ base.Initialize();
+ }
+
+ public override void OnRemove()
+ {
+ transform = null;
+ base.OnRemove();
+ }
+
+ public IItemComponent Get(string slot)
+ {
+ return _GetSlot(slot).Item;
+ }
+
+ public IInventorySlot GetSlot(string slot)
+ {
+ return slots[slot];
+ }
+
+ // Private version that returns our concrete implementation.
+ private InventorySlot _GetSlot(string slot)
+ {
+ return slots[slot];
+ }
+
+ public bool PutInSlot(string slot, IItemComponent item)
+ {
+ var inventorySlot = _GetSlot(slot);
+ if (inventorySlot.Item != null)
+ {
+ return false;
+ }
+
+ inventorySlot.Item = item;
+ item.EquippedToSlot(inventorySlot);
+ return true;
+ }
+
+ public bool DropSlot(string slot)
+ {
+ var inventorySlot = _GetSlot(slot);
+ var item = inventorySlot.Item;
+ if (item == null || !container.Remove(item.Owner))
+ {
+ return false;
+ }
+
+ item.RemovedFromSlot();
+ inventorySlot.Item = null;
+
+ // TODO: The item should be dropped to the container our owner is in, if any.
+ var itemTransform = item.Owner.GetComponent();
+ itemTransform.LocalPosition = transform.LocalPosition;
+ return true;
+ }
+
+ public void AddSlot(string slot)
+ {
+ if (slots.ContainsKey(slot))
+ {
+
+ }
+ }
+
+ public void RemoveSlot(string slot)
+ {
+ throw new NotImplementedException();
+ }
+
+ private class InventorySlot : IInventorySlot
+ {
+ public IItemComponent Item { get; set; }
+ public string Name { get; }
+ public IInventoryComponent Owner { get; }
+
+ public InventorySlot(string name, IInventoryComponent owner)
+ {
+ Name = name;
+ Owner = owner;
+ }
+ }
+ }
+}
diff --git a/Content.Server/GameObjects/Components/Items/ItemComponent.cs b/Content.Server/GameObjects/Components/Items/ItemComponent.cs
new file mode 100644
index 0000000000..0571ab8492
--- /dev/null
+++ b/Content.Server/GameObjects/Components/Items/ItemComponent.cs
@@ -0,0 +1,35 @@
+using Content.Server.Interfaces.GameObjects;
+using SS14.Shared.GameObjects;
+using SS14.Shared.Interfaces.GameObjects;
+using System;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public class ItemComponent : Component, IItemComponent
+ {
+ public override string Name => "Item";
+
+ ///
+ public IInventorySlot ContainingSlot { get; private set; }
+
+ public void RemovedFromSlot()
+ {
+ if (ContainingSlot == null)
+ {
+ throw new InvalidOperationException("Item is not in a slot.");
+ }
+
+ ContainingSlot = null;
+ }
+
+ public void EquippedToSlot(IInventorySlot slot)
+ {
+ if (ContainingSlot != null)
+ {
+ throw new InvalidOperationException("Item is already in a slot.");
+ }
+
+ ContainingSlot = slot;
+ }
+ }
+}
diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs
new file mode 100644
index 0000000000..881f30328b
--- /dev/null
+++ b/Content.Server/Interfaces/GameObjects/Components/Items/IHandsComponent.cs
@@ -0,0 +1,50 @@
+using SS14.Shared.Interfaces.GameObjects;
+using System.Collections.Generic;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public interface IHandsComponent : IComponent
+ {
+ ///
+ /// The hand index of the currently active hand.
+ ///
+ string ActiveIndex { get; }
+
+ ///
+ /// Enumerates over every held item.
+ ///
+ IEnumerable GetAllHands();
+
+ ///
+ /// Gets the item held by a hand.
+ ///
+ /// The index of the hand to get.
+ /// The item in the held, null if no item is held
+ IItemComponent GetHand(string index);
+
+ ///
+ /// Puts an item into any empty hand, preferring the active hand.
+ ///
+ /// The item to put in a hand.
+ /// True if the item was inserted, false otherwise.
+ bool PutInHand(IItemComponent item);
+
+ ///
+ /// Puts an item into a specific hand.
+ ///
+ /// The item to put in the hand.
+ /// The index of the hand to put the item into.
+ ///
+ /// If true and the provided hand is full, the method will fall back to
+ ///
+ /// True if the item was inserted into a hand, false otherwise.
+ bool PutInHand(IItemComponent item, string index, bool fallback=true);
+
+ ///
+ /// Drops an item on the ground, removing it from the hand.
+ ///
+ /// The hand to drop from.
+ /// True if an item was successfully dropped, false otherwise.
+ bool Drop(string index);
+ }
+}
diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs
new file mode 100644
index 0000000000..4f3247ecdf
--- /dev/null
+++ b/Content.Server/Interfaces/GameObjects/Components/Items/IInventoryComponent.cs
@@ -0,0 +1,84 @@
+using SS14.Server.Interfaces.GameObjects;
+using SS14.Shared.Interfaces.GameObjects;
+using System;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public interface IInventoryComponent : IComponent
+ {
+ ///
+ /// Gets the item in the specified slot.
+ ///
+ /// The slot to get the item for.
+ /// Null if the slot is empty, otherwise the item.
+ IItemComponent Get(string slot);
+
+ ///
+ /// Gets the slot with specified name.
+ /// This gets the slot, NOT the item contained therein.
+ ///
+ /// The name of the slot to get.
+ IInventorySlot GetSlot(string slot);
+
+ ///
+ /// Puts an item in a slot.
+ ///
+ ///
+ /// This will fail if there is already an item in the specified slot.
+ ///
+ /// The slot to put the item in.
+ /// The item to insert into the slot.
+ /// True if the item was successfully inserted, false otherwise.
+ bool PutInSlot(string slot, IItemComponent item);
+
+ ///
+ /// Drops the item in a slot.
+ ///
+ /// The slot to drop the item from.
+ /// True if an item was dropped, false otherwise.
+ bool DropSlot(string slot);
+
+ ///
+ /// Adds a new slot to this inventory component.
+ ///
+ /// The name of the slot to add.
+ ///
+ /// Thrown if the slot with specified name already exists.
+ ///
+ void AddSlot(string slot);
+
+ ///
+ /// Removes a slot from this inventory component.
+ ///
+ ///
+ /// If the slot contains an item, the item is dropped.
+ ///
+ /// The name of the slot to remove.
+ void RemoveSlot(string slot);
+
+ ///
+ ///
+ ///
+ ///
+ ///
+ bool HasSlot(string slot);
+ }
+
+ public interface IInventorySlot
+ {
+ ///
+ /// The name of the slot.
+ ///
+ string Name { get; }
+
+ ///
+ /// The item contained in the slot, can be null.
+ ///
+ IItemComponent Item { get; }
+
+ ///
+ /// The component owning us.
+ ///
+ IInventoryComponent Owner { get; }
+ }
+}
diff --git a/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs b/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs
new file mode 100644
index 0000000000..cd54ef375c
--- /dev/null
+++ b/Content.Server/Interfaces/GameObjects/Components/Items/IItemComponent.cs
@@ -0,0 +1,22 @@
+using SS14.Shared.Interfaces.GameObjects;
+
+namespace Content.Server.Interfaces.GameObjects
+{
+ public interface IItemComponent : IComponent
+ {
+ ///
+ /// The inventory slot this item is stored in, if any.
+ ///
+ IInventorySlot ContainingSlot { get; }
+
+ ///
+ /// Called when the item is removed from its inventory slot.
+ ///
+ void RemovedFromSlot();
+
+ ///
+ /// Called when the item is inserted into a new inventory slot.
+ ///
+ void EquippedToSlot(IInventorySlot slot);
+ }
+}