| 124 | ); |
| 125 | |
| 126 | const methodAttrs = (envelope: JsonRpcEnvelope): Record<string, unknown> => { |
| 127 | const params = envelope.params ?? {}; |
| 128 | return Match.value(envelope.method).pipe( |
| 129 | Match.when("initialize", () => |
| 130 | Option.match(decodeInitializeParams(params), { |
| 131 | onNone: () => ({}) as Record<string, unknown>, |
| 132 | onSome: (init) => ({ |
| 133 | ...(init.protocolVersion && { "mcp.client.protocol_version": init.protocolVersion }), |
| 134 | ...(init.clientInfo?.name && { "mcp.client.name": init.clientInfo.name }), |
| 135 | ...(init.clientInfo?.version && { "mcp.client.version": init.clientInfo.version }), |
| 136 | ...(init.clientInfo?.title && { "mcp.client.title": init.clientInfo.title }), |
| 137 | "mcp.client.capability.keys": Object.keys(init.capabilities ?? {}) |
| 138 | .sort() |
| 139 | .join(","), |
| 140 | }), |
| 141 | }), |
| 142 | ), |
| 143 | Match.when("tools/call", () => |
| 144 | Option.match(decodeNamedParams(params), { |
| 145 | onNone: () => ({}) as Record<string, unknown>, |
| 146 | onSome: ({ name }) => (name ? { "mcp.tool.name": name } : {}), |
| 147 | }), |
| 148 | ), |
| 149 | Match.whenOr("resources/read", "resources/subscribe", () => |
| 150 | Option.match(decodeUriParams(params), { |
| 151 | onNone: () => ({}) as Record<string, unknown>, |
| 152 | onSome: ({ uri }) => (uri ? { "mcp.resource.uri": uri } : {}), |
| 153 | }), |
| 154 | ), |
| 155 | Match.when("prompts/get", () => |
| 156 | Option.match(decodeNamedParams(params), { |
| 157 | onNone: () => ({}) as Record<string, unknown>, |
| 158 | onSome: ({ name }) => (name ? { "mcp.prompt.name": name } : {}), |
| 159 | }), |
| 160 | ), |
| 161 | Match.option, |
| 162 | Option.getOrElse(() => ({}) as Record<string, unknown>), |
| 163 | ); |
| 164 | }; |
| 165 | |
| 166 | const replyAttrs = (envelope: JsonRpcEnvelope): Record<string, unknown> => { |
| 167 | if (!envelope.result || envelope.method) return {}; |