diff --git a/plexus-protocol.cabal b/plexus-protocol.cabal
--- a/plexus-protocol.cabal
+++ b/plexus-protocol.cabal
@@ -1,6 +1,6 @@
 cabal-version:      3.0
 name:               plexus-protocol
-version:            0.3.2.0
+version:            0.5.0.0
 synopsis:           Plexus RPC protocol types and client
 license:            MIT
 author:
diff --git a/src/Plexus/Schema/Recursive.hs b/src/Plexus/Schema/Recursive.hs
--- a/src/Plexus/Schema/Recursive.hs
+++ b/src/Plexus/Schema/Recursive.hs
@@ -34,6 +34,11 @@
   , PluginHash
   , SchemaResult(..)
 
+    -- * Deprecation Metadata (IR-5)
+  , DeprecationInfo(..)
+  , ParamSchema(..)
+  , MethodRole(..)
+
     -- * Queries
   , isHubActivation
   , isLeafActivation
@@ -49,12 +54,114 @@
 import Control.Applicative ((<|>))
 
 import Data.Aeson
-import Data.Maybe (fromMaybe)
+import Data.Aeson.Types (Parser)
+import Data.Maybe (catMaybes, fromMaybe)
 import Data.Text (Text)
 import qualified Data.Text as T
 import GHC.Generics (Generic)
 
 -- ============================================================================
+-- Deprecation Metadata (IR-5)
+-- ============================================================================
+
+-- | Structured deprecation metadata attached to activations, methods, and
+--   parameter fields.
+--
+--   All three text fields use JSON snake_case on the wire
+--   (@since@, @removed_in@, @message@). Producers emitted before IR-2
+--   may omit the outer field entirely; consumers should use @.:?@ so a
+--   missing value deserializes as 'Nothing' on the containing record.
+data DeprecationInfo = DeprecationInfo
+  { depSince     :: Text   -- ^ Version the surface became deprecated.
+  , depRemovedIn :: Text   -- ^ Version at which the surface will be removed.
+  , depMessage   :: Text   -- ^ Human-readable migration guidance.
+  }
+  deriving stock (Show, Eq, Generic)
+
+instance FromJSON DeprecationInfo where
+  parseJSON = withObject "DeprecationInfo" $ \o -> DeprecationInfo
+    <$> o .:  "since"
+    <*> o .:  "removed_in"
+    <*> o .:  "message"
+
+instance ToJSON DeprecationInfo where
+  toJSON DeprecationInfo{..} = object
+    [ "since"      .= depSince
+    , "removed_in" .= depRemovedIn
+    , "message"    .= depMessage
+    ]
+
+-- | Structural role of a method in the activation graph (IR-2 / IR-3).
+--
+--   Mirrors the Rust @plexus_core::MethodRole@ enum. Tagged on the wire
+--   with a @kind@ discriminator and @snake_case@ variant names:
+--
+--   @
+--   {"kind": "rpc"}
+--   {"kind": "static_child"}
+--   {"kind": "dynamic_child", "list_method": "planet_names", "search_method": null}
+--   @
+--
+--   Defaults to 'MethodRoleRpc' when absent so pre-IR servers deserialize
+--   cleanly (see 'MethodSchema.methodRole' parser).
+data MethodRole
+  = MethodRoleRpc
+  | MethodRoleStaticChild
+  | MethodRoleDynamicChild
+      { listMethod   :: Maybe Text
+      , searchMethod :: Maybe Text
+      }
+  deriving stock (Show, Eq, Generic)
+
+instance FromJSON MethodRole where
+  parseJSON = withObject "MethodRole" $ \o -> do
+    kind <- o .: "kind" :: Parser Text
+    case kind of
+      "rpc"           -> pure MethodRoleRpc
+      "static_child"  -> pure MethodRoleStaticChild
+      "dynamic_child" -> MethodRoleDynamicChild
+        <$> o .:? "list_method"
+        <*> o .:? "search_method"
+      other -> fail $ "Unknown MethodRole kind: " <> T.unpack other
+
+instance ToJSON MethodRole where
+  toJSON MethodRoleRpc         = object ["kind" .= ("rpc" :: Text)]
+  toJSON MethodRoleStaticChild = object ["kind" .= ("static_child" :: Text)]
+  toJSON (MethodRoleDynamicChild lm sm) =
+    object $ ("kind" .= ("dynamic_child" :: Text)) : catMaybes
+      [ ("list_method"   .=) <$> lm
+      , ("search_method" .=) <$> sm
+      ]
+
+-- | Shallow parameter schema with optional per-field deprecation.
+--
+--   Not every producer emits this; synapse treats 'Nothing' as "no
+--   per-field metadata available" and falls back to the raw
+--   'methodParams' 'Value' for legacy rendering.
+data ParamSchema = ParamSchema
+  { paramName         :: Text
+  , paramDescription  :: Maybe Text
+  , paramRequired     :: Bool
+  , paramDeprecation  :: Maybe DeprecationInfo
+  }
+  deriving stock (Show, Eq, Generic)
+
+instance FromJSON ParamSchema where
+  parseJSON = withObject "ParamSchema" $ \o -> ParamSchema
+    <$> o .:  "name"
+    <*> o .:? "description"
+    <*> o .:? "required" .!= False
+    <*> o .:? "deprecation"
+
+instance ToJSON ParamSchema where
+  toJSON ParamSchema{..} = object
+    [ "name"        .= paramName
+    , "description" .= paramDescription
+    , "required"    .= paramRequired
+    , "deprecation" .= paramDeprecation
+    ]
+
+-- ============================================================================
 -- Core Types
 -- ============================================================================
 
@@ -96,6 +203,9 @@
   , methodBidirectional   :: Bool         -- ^ True if method uses a bidirectional channel
   , methodRequestType     :: Maybe Value  -- ^ JSON Schema for the server→client request type (when bidirectional)
   , methodResponseType    :: Maybe Value  -- ^ JSON Schema for the client→server response type (when bidirectional)
+  , methodDeprecation     :: Maybe DeprecationInfo  -- ^ Deprecation info, if any (IR-5)
+  , methodParamSchemas    :: Maybe [ParamSchema]    -- ^ Optional structured param info with per-field deprecations (IR-5)
+  , methodRole            :: MethodRole             -- ^ Structural role in the activation graph (IR-2 / IR-3); defaults to 'MethodRoleRpc'
   }
   deriving stock (Show, Eq, Generic)
 
@@ -110,6 +220,9 @@
     <*> o .:? "bidirectional"  .!= False
     <*> o .:? "request_type"
     <*> o .:? "response_type"
+    <*> o .:? "deprecation"
+    <*> o .:? "param_schemas"
+    <*> o .:? "role" .!= MethodRoleRpc
 
 instance ToJSON MethodSchema where
   toJSON MethodSchema{..} = object
@@ -122,6 +235,9 @@
     , "bidirectional"  .= methodBidirectional
     , "request_type"   .= methodRequestType
     , "response_type"  .= methodResponseType
+    , "deprecation"    .= methodDeprecation
+    , "param_schemas"  .= methodParamSchemas
+    , "role"           .= methodRole
     ]
 
 -- | Shallow plugin schema (what we receive from {backend}.schema)
@@ -136,6 +252,7 @@
   , psHash            :: PluginHash
   , psMethods         :: [MethodSchema]
   , psChildren        :: Maybe [ChildSummary]  -- ^ Nothing = leaf, Just = hub activation
+  , psDeprecation     :: Maybe DeprecationInfo -- ^ Activation-level deprecation (IR-5)
   }
   deriving stock (Show, Eq, Generic)
 
@@ -148,6 +265,7 @@
     <*> o .: "hash"
     <*> o .:? "methods" .!= []
     <*> o .:? "children"
+    <*> o .:? "deprecation"
 
 instance ToJSON PluginSchema where
   toJSON PluginSchema{..} = object
@@ -158,6 +276,7 @@
     , "hash"             .= psHash
     , "methods"          .= psMethods
     , "children"         .= psChildren
+    , "deprecation"      .= psDeprecation
     ]
 
 -- | Result of a schema query - can be either a full plugin or just a method
