@@ -13,33 +13,31 @@ describe('MCP Server PII Filtering', () => {
1313 vi . clearAllMocks ( ) ;
1414 } ) ;
1515
16- describe ( 'Integration Tests' , ( ) => {
16+ describe ( 'Integration Tests - Network PII ' , ( ) => {
1717 let mockMcpServer : ReturnType < typeof createMockMcpServer > ;
18- let wrappedMcpServer : ReturnType < typeof createMockMcpServer > ;
1918 let mockTransport : ReturnType < typeof createMockTransport > ;
2019
2120 beforeEach ( ( ) => {
2221 mockMcpServer = createMockMcpServer ( ) ;
23- wrappedMcpServer = wrapMcpServerWithSentry ( mockMcpServer ) ;
2422 mockTransport = createMockTransport ( ) ;
2523 mockTransport . sessionId = 'test-session-123' ;
2624 } ) ;
2725
28- it ( 'should include PII data when sendDefaultPii is true' , async ( ) => {
29- // Mock client with sendDefaultPii: true
26+ it ( 'should include network PII when sendDefaultPii is true' , async ( ) => {
3027 getClientSpy . mockReturnValue ( {
3128 getOptions : ( ) => ( { sendDefaultPii : true } ) ,
3229 getDsn : ( ) => ( { publicKey : 'test-key' , host : 'test-host' } ) ,
3330 emit : vi . fn ( ) ,
3431 } as unknown as ReturnType < typeof currentScopes . getClient > ) ;
3532
33+ const wrappedMcpServer = wrapMcpServerWithSentry ( mockMcpServer ) ;
3634 await wrappedMcpServer . connect ( mockTransport ) ;
3735
3836 const jsonRpcRequest = {
3937 jsonrpc : '2.0' ,
4038 method : 'tools/call' ,
4139 id : 'req-pii-true' ,
42- params : { name : 'weather' , arguments : { location : 'London' , units : 'metric' } } ,
40+ params : { name : 'weather' , arguments : { location : 'London' } } ,
4341 } ;
4442
4543 const extraWithClientInfo = {
@@ -51,35 +49,31 @@ describe('MCP Server PII Filtering', () => {
5149
5250 mockTransport . onmessage ?.( jsonRpcRequest , extraWithClientInfo ) ;
5351
54- expect ( startInactiveSpanSpy ) . toHaveBeenCalledWith ( {
55- name : 'tools/call weather' ,
56- op : 'mcp.server' ,
57- forceTransaction : true ,
58- attributes : expect . objectContaining ( {
59- 'client.address' : '192.168.1.100' ,
60- 'client.port' : 54321 ,
61- 'mcp.request.argument.location' : '"London"' ,
62- 'mcp.request.argument.units' : '"metric"' ,
63- 'mcp.tool.name' : 'weather' ,
52+ expect ( startInactiveSpanSpy ) . toHaveBeenCalledWith (
53+ expect . objectContaining ( {
54+ attributes : expect . objectContaining ( {
55+ 'client.address' : '192.168.1.100' ,
56+ 'client.port' : 54321 ,
57+ } ) ,
6458 } ) ,
65- } ) ;
59+ ) ;
6660 } ) ;
6761
68- it ( 'should exclude PII data when sendDefaultPii is false' , async ( ) => {
69- // Mock client with sendDefaultPii: false
62+ it ( 'should exclude network PII when sendDefaultPii is false' , async ( ) => {
7063 getClientSpy . mockReturnValue ( {
7164 getOptions : ( ) => ( { sendDefaultPii : false } ) ,
7265 getDsn : ( ) => ( { publicKey : 'test-key' , host : 'test-host' } ) ,
7366 emit : vi . fn ( ) ,
7467 } as unknown as ReturnType < typeof currentScopes . getClient > ) ;
7568
69+ const wrappedMcpServer = wrapMcpServerWithSentry ( mockMcpServer ) ;
7670 await wrappedMcpServer . connect ( mockTransport ) ;
7771
7872 const jsonRpcRequest = {
7973 jsonrpc : '2.0' ,
8074 method : 'tools/call' ,
8175 id : 'req-pii-false' ,
82- params : { name : 'weather' , arguments : { location : 'London' , units : 'metric' } } ,
76+ params : { name : 'weather' , arguments : { location : 'London' } } ,
8377 } ;
8478
8579 const extraWithClientInfo = {
@@ -96,8 +90,6 @@ describe('MCP Server PII Filtering', () => {
9690 attributes : expect . not . objectContaining ( {
9791 'client.address' : expect . anything ( ) ,
9892 'client.port' : expect . anything ( ) ,
99- 'mcp.request.argument.location' : expect . anything ( ) ,
100- 'mcp.request.argument.units' : expect . anything ( ) ,
10193 } ) ,
10294 } ) ,
10395 ) ;
@@ -111,130 +103,41 @@ describe('MCP Server PII Filtering', () => {
111103 } ) ,
112104 ) ;
113105 } ) ;
114-
115- it ( 'should filter tool result content when sendDefaultPii is false' , async ( ) => {
116- // Mock client with sendDefaultPii: false
117- getClientSpy . mockReturnValue ( {
118- getOptions : ( ) => ( { sendDefaultPii : false } ) ,
119- } as ReturnType < typeof currentScopes . getClient > ) ;
120-
121- await wrappedMcpServer . connect ( mockTransport ) ;
122-
123- const mockSpan = {
124- setAttributes : vi . fn ( ) ,
125- setStatus : vi . fn ( ) ,
126- end : vi . fn ( ) ,
127- } as unknown as ReturnType < typeof tracingModule . startInactiveSpan > ;
128- startInactiveSpanSpy . mockReturnValueOnce ( mockSpan ) ;
129-
130- const toolCallRequest = {
131- jsonrpc : '2.0' ,
132- method : 'tools/call' ,
133- id : 'req-tool-result-filtered' ,
134- params : { name : 'weather-lookup' } ,
135- } ;
136-
137- mockTransport . onmessage ?.( toolCallRequest , { } ) ;
138-
139- const toolResponse = {
140- jsonrpc : '2.0' ,
141- id : 'req-tool-result-filtered' ,
142- result : {
143- content : [ { type : 'text' , text : 'Sensitive weather data for London' } ] ,
144- isError : false ,
145- } ,
146- } ;
147-
148- mockTransport . send ?.( toolResponse ) ;
149-
150- // Tool result content should be filtered out, but metadata should remain
151- const setAttributesCall = mockSpan . setAttributes . mock . calls [ 0 ] ?. [ 0 ] ;
152- expect ( setAttributesCall ) . toBeDefined ( ) ;
153- expect ( setAttributesCall ) . not . toHaveProperty ( 'mcp.tool.result.content' ) ;
154- expect ( setAttributesCall ) . toHaveProperty ( 'mcp.tool.result.is_error' , false ) ;
155- expect ( setAttributesCall ) . toHaveProperty ( 'mcp.tool.result.content_count' , 1 ) ;
156- } ) ;
157106 } ) ;
158107
159108 describe ( 'filterMcpPiiFromSpanData Function' , ( ) => {
160109 it ( 'should preserve all data when sendDefaultPii is true' , ( ) => {
161110 const spanData = {
162111 'client.address' : '192.168.1.100' ,
163112 'client.port' : 54321 ,
164- 'mcp.request.argument.location' : '"San Francisco"' ,
165- 'mcp.tool.result.content' : 'Weather data: 18°C' ,
166- 'mcp.tool.result.content_count' : 1 ,
167- 'mcp.prompt.result.description' : 'Code review prompt for sensitive analysis' ,
168- 'mcp.prompt.result.message_content' : 'Please review this confidential code.' ,
169- 'mcp.prompt.result.message_count' : 1 ,
170- 'mcp.resource.result.content' : 'Sensitive resource content' ,
171- 'mcp.logging.message' : 'User requested weather' ,
172113 'mcp.resource.uri' : 'file:///private/docs/secret.txt' ,
173- 'mcp.method.name' : 'tools/call' , // Non-PII should remain
114+ 'mcp.method.name' : 'tools/call' ,
115+ 'mcp.tool.name' : 'weather' ,
174116 } ;
175117
176118 const result = filterMcpPiiFromSpanData ( spanData , true ) ;
177119
178- expect ( result ) . toEqual ( spanData ) ; // All data preserved
120+ expect ( result ) . toEqual ( spanData ) ;
179121 } ) ;
180122
181- it ( 'should remove PII data when sendDefaultPii is false' , ( ) => {
123+ it ( 'should only remove network PII when sendDefaultPii is false' , ( ) => {
182124 const spanData = {
183125 'client.address' : '192.168.1.100' ,
184126 'client.port' : 54321 ,
185- 'mcp.request.argument.location' : '"San Francisco"' ,
186- 'mcp.request.argument.units' : '"celsius"' ,
187- 'mcp.tool.result.content' : 'Weather data: 18°C' ,
188- 'mcp.tool.result.content_count' : 1 ,
189- 'mcp.prompt.result.description' : 'Code review prompt for sensitive analysis' ,
190- 'mcp.prompt.result.message_count' : 2 ,
191- 'mcp.prompt.result.0.role' : 'user' ,
192- 'mcp.prompt.result.0.content' : 'Sensitive prompt content' ,
193- 'mcp.prompt.result.1.role' : 'assistant' ,
194- 'mcp.prompt.result.1.content' : 'Another sensitive response' ,
195- 'mcp.resource.result.content_count' : 1 ,
196- 'mcp.resource.result.uri' : 'file:///private/file.txt' ,
197- 'mcp.resource.result.content' : 'Sensitive resource content' ,
198- 'mcp.logging.message' : 'User requested weather' ,
199127 'mcp.resource.uri' : 'file:///private/docs/secret.txt' ,
200- 'mcp.method.name' : 'tools/call' , // Non-PII should remain
201- 'mcp.session.id' : 'test-session-123' , // Non-PII should remain
128+ 'mcp.method.name' : 'tools/call' ,
129+ 'mcp.tool.name' : 'weather' ,
130+ 'mcp.session.id' : 'test-session-123' ,
202131 } ;
203132
204133 const result = filterMcpPiiFromSpanData ( spanData , false ) ;
205134
206- // Client info should be filtered
207135 expect ( result ) . not . toHaveProperty ( 'client.address' ) ;
208136 expect ( result ) . not . toHaveProperty ( 'client.port' ) ;
209-
210- // Request arguments should be filtered
211- expect ( result ) . not . toHaveProperty ( 'mcp.request.argument.location' ) ;
212- expect ( result ) . not . toHaveProperty ( 'mcp.request.argument.units' ) ;
213-
214- // Specific PII content attributes should be filtered
215- expect ( result ) . not . toHaveProperty ( 'mcp.tool.result.content' ) ;
216- expect ( result ) . not . toHaveProperty ( 'mcp.prompt.result.description' ) ;
217-
218- // Count attributes should remain as they don't contain sensitive content
219- expect ( result ) . toHaveProperty ( 'mcp.tool.result.content_count' , 1 ) ;
220- expect ( result ) . toHaveProperty ( 'mcp.prompt.result.message_count' , 2 ) ;
221-
222- // All tool and prompt result content should be filtered (including indexed attributes)
223- expect ( result ) . not . toHaveProperty ( 'mcp.prompt.result.0.role' ) ;
224- expect ( result ) . not . toHaveProperty ( 'mcp.prompt.result.0.content' ) ;
225- expect ( result ) . not . toHaveProperty ( 'mcp.prompt.result.1.role' ) ;
226- expect ( result ) . not . toHaveProperty ( 'mcp.prompt.result.1.content' ) ;
227-
228- expect ( result ) . toHaveProperty ( 'mcp.resource.result.content_count' , 1 ) ;
229- expect ( result ) . toHaveProperty ( 'mcp.resource.result.uri' , 'file:///private/file.txt' ) ;
230- expect ( result ) . toHaveProperty ( 'mcp.resource.result.content' , 'Sensitive resource content' ) ;
231-
232- // Other PII attributes should be filtered
233- expect ( result ) . not . toHaveProperty ( 'mcp.logging.message' ) ;
234137 expect ( result ) . not . toHaveProperty ( 'mcp.resource.uri' ) ;
235138
236- // Non-PII attributes should remain
237139 expect ( result ) . toHaveProperty ( 'mcp.method.name' , 'tools/call' ) ;
140+ expect ( result ) . toHaveProperty ( 'mcp.tool.name' , 'weather' ) ;
238141 expect ( result ) . toHaveProperty ( 'mcp.session.id' , 'test-session-123' ) ;
239142 } ) ;
240143
@@ -243,10 +146,11 @@ describe('MCP Server PII Filtering', () => {
243146 expect ( result ) . toEqual ( { } ) ;
244147 } ) ;
245148
246- it ( 'should handle span data with no PII attributes' , ( ) => {
149+ it ( 'should handle span data with no network PII attributes' , ( ) => {
247150 const spanData = {
248151 'mcp.method.name' : 'tools/list' ,
249152 'mcp.session.id' : 'test-session' ,
153+ 'mcp.tool.name' : 'weather' ,
250154 } ;
251155
252156 const result = filterMcpPiiFromSpanData ( spanData , false ) ;
0 commit comments