Skip to content

Commit 459e078

Browse files
RahulHereRahulHere
authored andcommitted
make format
1 parent b7940c8 commit 459e078

36 files changed

Lines changed: 1015 additions & 967 deletions

sdk/typescript/README.md

Lines changed: 125 additions & 99 deletions
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ The SDK supports the canonical listener-based configuration format that matches
138138
import {
139139
createRealDispatcher,
140140
createFilterChainFromConfig,
141-
CanonicalConfig
141+
CanonicalConfig,
142142
} from "@mcp/filter-sdk";
143143

144144
// Create dispatcher
@@ -152,20 +152,20 @@ const config: CanonicalConfig = {
152152
address: {
153153
socket_address: {
154154
address: "127.0.0.1",
155-
port_value: 9090
156-
}
155+
port_value: 9090,
156+
},
157157
},
158158
filter_chains: [
159159
{
160160
filters: [
161161
{ name: "http.codec", type: "http.codec" },
162162
{ name: "sse.codec", type: "sse.codec" },
163-
{ name: "json_rpc.dispatcher", type: "json_rpc.dispatcher" }
164-
]
165-
}
166-
]
167-
}
168-
]
163+
{ name: "json_rpc.dispatcher", type: "json_rpc.dispatcher" },
164+
],
165+
},
166+
],
167+
},
168+
],
169169
};
170170

171171
// Create filter chain from configuration
@@ -450,6 +450,7 @@ The SDK uses the canonical listener-based configuration format that matches the
450450
```
451451

452452
This format provides:
453+
453454
- Clear separation of network configuration (listeners) from processing logic (filter chains)
454455
- Support for multiple listeners on different ports
455456
- Consistent structure across C++ and TypeScript implementations
@@ -502,32 +503,36 @@ The `FilterChain` class provides a Koffi-based FFI bridge to C++ filter implemen
502503
#### **Quick Start**
503504

504505
```typescript
505-
import { FilterChain } from './filter-chain-ffi';
506-
import { createRealDispatcher } from './mcp-filter-api';
506+
import { FilterChain } from "./filter-chain-ffi";
507+
import { createRealDispatcher } from "./mcp-filter-api";
507508

508509
// Create dispatcher
509510
const dispatcher = createRealDispatcher();
510511

511512
// Define filter configuration
512513
const config = {
513-
listeners: [{
514-
name: 'filters',
515-
filter_chains: [{
516-
filters: [
517-
{ type: 'rate_limiter', name: 'limiter', config: { rps: 100 } },
518-
{ type: 'circuit_breaker', name: 'breaker', config: { threshold: 5 } },
519-
{ type: 'metrics', name: 'metrics' }
520-
]
521-
}]
522-
}]
514+
listeners: [
515+
{
516+
name: "filters",
517+
filter_chains: [
518+
{
519+
filters: [
520+
{ type: "rate_limiter", name: "limiter", config: { rps: 100 } },
521+
{ type: "circuit_breaker", name: "breaker", config: { threshold: 5 } },
522+
{ type: "metrics", name: "metrics" },
523+
],
524+
},
525+
],
526+
},
527+
],
523528
};
524529

525530
// Create and use filter chain
526531
const chain = new FilterChain(dispatcher, config);
527532
await chain.initialize();
528533

529-
const result = await chain.processIncoming({ method: 'test' });
530-
console.log('Filter decision:', result.decision); // 0=ALLOW, 1=DENY
534+
const result = await chain.processIncoming({ method: "test" });
535+
console.log("Filter decision:", result.decision); // 0=ALLOW, 1=DENY
531536

532537
await chain.shutdown();
533538
chain.destroy();
@@ -551,44 +556,49 @@ chain.destroy();
551556
#### **API Reference**
552557

553558
**Lifecycle:**
559+
554560
```typescript
555-
constructor(dispatcher, config) // Create chain
556-
await initialize() // Start processing
557-
await shutdown() // Stop gracefully
558-
destroy() // Release resources
561+
constructor(dispatcher, config); // Create chain
562+
await initialize(); // Start processing
563+
await shutdown(); // Stop gracefully
564+
destroy(); // Release resources
559565
```
560566

561567
**Message Processing:**
568+
562569
```typescript
563-
await processIncoming(message) // Filter incoming message
564-
await processOutgoing(message) // Filter outgoing message
570+
await processIncoming(message); // Filter incoming message
571+
await processOutgoing(message); // Filter outgoing message
565572
```
566573

567574
**Metrics & Stats:**
575+
568576
```typescript
569577
await getChainStats() // Get chain statistics
570578
await getMetrics(filterName?) // Get filter metrics
571579
```
572580
573581
**Dynamic Configuration:**
582+
574583
```typescript
575-
await enableFilter(name) // Enable a filter
576-
await disableFilter(name) // Disable a filter
577-
await exportConfig() // Export current config
584+
await enableFilter(name); // Enable a filter
585+
await disableFilter(name); // Disable a filter
586+
await exportConfig(); // Export current config
578587
```
579588
580589
**Validation:**
590+
581591
```typescript
582-
FilterChain.validateConfig(config) // Validate before creation
592+
FilterChain.validateConfig(config); // Validate before creation
583593
```
584594
585595
#### **Usage with Official MCP SDK**
586596
587597
The FilterChain can be wrapped in a custom transport to use with the official MCP SDK:
588598
589599
```typescript
590-
import { FilterChain } from './filter-chain-ffi';
591-
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
600+
import { FilterChain } from "./filter-chain-ffi";
601+
import { StdioServerTransport } from "@modelcontextprotocol/sdk/server/stdio.js";
592602

593603
class FilteredTransport {
594604
constructor(baseTransport, filterChain) {
@@ -598,16 +608,18 @@ class FilteredTransport {
598608

599609
async send(message) {
600610
const result = await this.filterChain.processOutgoing(message);
601-
if (result.decision === 0) { // ALLOW
611+
if (result.decision === 0) {
612+
// ALLOW
602613
return this.baseTransport.send(result.transformedMessage || message);
603614
}
604615
throw new Error(`Message blocked: ${result.reason}`);
605616
}
606617

607618
onMessage(handler) {
608-
this.baseTransport.onMessage(async (message) => {
619+
this.baseTransport.onMessage(async message => {
609620
const result = await this.filterChain.processIncoming(message);
610-
if (result.decision === 0) { // ALLOW
621+
if (result.decision === 0) {
622+
// ALLOW
611623
handler(result.transformedMessage || message);
612624
}
613625
});
@@ -652,18 +664,22 @@ const stdioTransport = new StdioServerTransport();
652664
const transport = new GopherFilteredTransport(stdioTransport, {
653665
dispatcherHandle: dispatcher,
654666
filterConfig: {
655-
listeners: [{
656-
name: "hybrid_filters",
657-
filter_chains: [{
658-
filters: [
659-
{ type: "rate_limiter", name: "limiter", config: { rps: 100 } },
660-
{ type: "circuit_breaker", name: "breaker", config: { threshold: 5 } },
661-
{ type: "metrics", name: "metrics", config: { export_port: 9090 } }
662-
]
663-
}]
664-
}]
667+
listeners: [
668+
{
669+
name: "hybrid_filters",
670+
filter_chains: [
671+
{
672+
filters: [
673+
{ type: "rate_limiter", name: "limiter", config: { rps: 100 } },
674+
{ type: "circuit_breaker", name: "breaker", config: { threshold: 5 } },
675+
{ type: "metrics", name: "metrics", config: { export_port: 9090 } },
676+
],
677+
},
678+
],
679+
},
680+
],
665681
},
666-
debugLogging: false
682+
debugLogging: false,
667683
});
668684

669685
// Use with MCP SDK server
@@ -705,30 +721,34 @@ Note: In hybrid SDK mode, the `address` field is **optional** since the SDK tran
705721
706722
```json
707723
{
708-
"listeners": [{
709-
"name": "hybrid_filters",
710-
"filter_chains": [{
711-
"name": "default",
712-
"filters": [
713-
{
714-
"name": "rate_limiter",
715-
"type": "rate_limiter",
716-
"config": {
717-
"requests_per_second": 100,
718-
"burst_size": 20
719-
}
720-
},
724+
"listeners": [
725+
{
726+
"name": "hybrid_filters",
727+
"filter_chains": [
721728
{
722-
"name": "circuit_breaker",
723-
"type": "circuit_breaker",
724-
"config": {
725-
"failure_threshold": 5,
726-
"timeout_ms": 60000
727-
}
729+
"name": "default",
730+
"filters": [
731+
{
732+
"name": "rate_limiter",
733+
"type": "rate_limiter",
734+
"config": {
735+
"requests_per_second": 100,
736+
"burst_size": 20
737+
}
738+
},
739+
{
740+
"name": "circuit_breaker",
741+
"type": "circuit_breaker",
742+
"config": {
743+
"failure_threshold": 5,
744+
"timeout_ms": 60000
745+
}
746+
}
747+
]
728748
}
729749
]
730-
}]
731-
}]
750+
}
751+
]
732752
}
733753
```
734754
@@ -737,18 +757,18 @@ Note: In hybrid SDK mode, the `address` field is **optional** since the SDK tran
737757
```typescript
738758
// Get metrics
739759
const metrics = await transport.getMetrics();
740-
console.log('Total processed:', metrics.chain.requests_total);
760+
console.log("Total processed:", metrics.chain.requests_total);
741761

742762
// Enable/disable filters
743-
await transport.setFilterEnabled('limiter', false); // Disable rate limiter
744-
await transport.setFilterEnabled('breaker', true); // Enable circuit breaker
763+
await transport.setFilterEnabled("limiter", false); // Disable rate limiter
764+
await transport.setFilterEnabled("breaker", true); // Enable circuit breaker
745765

746766
// Export current configuration
747767
const config = await transport.exportFilterConfig();
748768

749769
// Get queue stats (for backpressure monitoring)
750770
const queueStats = transport.getQueueStats();
751-
console.log('Queued messages:', queueStats.size);
771+
console.log("Queued messages:", queueStats.size);
752772
```
753773
754774
#### **Error Handling**
@@ -758,10 +778,10 @@ try {
758778
await transport.send(message);
759779
} catch (error) {
760780
if (error instanceof FilterDeniedError) {
761-
console.log('Message blocked by filter:', error.reason);
781+
console.log("Message blocked by filter:", error.reason);
762782
// Handle rate limiting, circuit breaker open, etc.
763783
} else {
764-
console.error('Transport error:', error);
784+
console.error("Transport error:", error);
765785
}
766786
}
767787
```
@@ -783,18 +803,22 @@ app.post("/sse", async (req, res) => {
783803
const transport = new GopherFilteredTransport(sseTransport, {
784804
dispatcherHandle: dispatcher,
785805
filterConfig: {
786-
listeners: [{
787-
name: "http_filters",
788-
filter_chains: [{
789-
filters: [
790-
{ type: "rate_limiter", name: "limiter", config: { rps: 50 } },
791-
{ type: "circuit_breaker", name: "breaker", config: { threshold: 3 } },
792-
{ type: "metrics", name: "metrics" }
793-
]
794-
}]
795-
}]
806+
listeners: [
807+
{
808+
name: "http_filters",
809+
filter_chains: [
810+
{
811+
filters: [
812+
{ type: "rate_limiter", name: "limiter", config: { rps: 50 } },
813+
{ type: "circuit_breaker", name: "breaker", config: { threshold: 3 } },
814+
{ type: "metrics", name: "metrics" },
815+
],
816+
},
817+
],
818+
},
819+
],
796820
},
797-
onValidationWarning: (warnings) => console.warn('Filter warnings:', warnings)
821+
onValidationWarning: warnings => console.warn("Filter warnings:", warnings),
798822
});
799823

800824
const server = new Server({ name: "http-server", version: "1.0.0" });
@@ -807,17 +831,19 @@ app.listen(3000);
807831
#### **Migration from Pure SDK**
808832
809833
**Before (Pure SDK):**
834+
810835
```typescript
811836
const transport = new StdioServerTransport();
812837
await server.connect(transport);
813838
```
814839
815840
**After (With Gopher Filters - One Line Change!):**
841+
816842
```typescript
817-
const transport = new GopherFilteredTransport(
818-
new StdioServerTransport(),
819-
{ dispatcherHandle: dispatcher, filterConfig: config }
820-
);
843+
const transport = new GopherFilteredTransport(new StdioServerTransport(), {
844+
dispatcherHandle: dispatcher,
845+
filterConfig: config,
846+
});
821847
await server.connect(transport);
822848
```
823849
@@ -831,14 +857,14 @@ await server.connect(transport);
831857
832858
#### **Comparison: Native vs Hybrid Approach**
833859
834-
| Aspect | Native C++ | Hybrid SDK |
835-
|--------|---------------------|---------------------|
836-
| Protocol | Custom C++ | Official SDK |
837-
| Filters | C++ | C++ (via wrapper) |
838-
| Overhead | ~0.5ms | ~0.66ms |
839-
| SDK Updates | Manual | Automatic |
840-
| Complexity | High | Low |
841-
| Use Case | Full control | Quick adoption |
860+
| Aspect | Native C++ | Hybrid SDK |
861+
| ----------- | ------------ | ----------------- |
862+
| Protocol | Custom C++ | Official SDK |
863+
| Filters | C++ | C++ (via wrapper) |
864+
| Overhead | ~0.5ms | ~0.66ms |
865+
| SDK Updates | Manual | Automatic |
866+
| Complexity | High | Low |
867+
| Use Case | Full control | Quick adoption |
842868
843869
See `examples/configs/hybrid-wrapper-config.json` for complete configuration examples.
844870

0 commit comments

Comments
 (0)