@@ -678,354 +678,7 @@ type Claims struct {
678
678
}
679
679
```
680
680
681
- ## Client Integration
682
681
683
- ### Go HTTP Client
684
-
685
- ``` go
686
- package main
687
-
688
- import (
689
- " context"
690
- " log"
691
-
692
- " github.com/mark3labs/mcp-go/client"
693
- )
694
-
695
- func main () {
696
- // Create HTTP client
697
- c := client.NewHTTPClient (" http://localhost:8080/mcp" )
698
-
699
- // Add authentication
700
- c.SetHeader (" Authorization" , " Bearer your-jwt-token" )
701
-
702
- // Set custom headers
703
- c.SetHeader (" X-API-Version" , " v1" )
704
- c.SetHeader (" X-Client-ID" , " my-app" )
705
-
706
- ctx := context.Background ()
707
-
708
- // Initialize connection
709
- if err := c.Initialize (ctx); err != nil {
710
- log.Fatal (err)
711
- }
712
-
713
- // List tools
714
- tools , err := c.ListTools (ctx)
715
- if err != nil {
716
- log.Fatal (err)
717
- }
718
-
719
- log.Printf (" Available tools: %d " , len (tools.Tools ))
720
-
721
- // Call tool
722
- result , err := c.CallTool (ctx, mcp.CallToolRequest {
723
- Params: mcp.CallToolRequestParams {
724
- Name: " search_users" ,
725
- Arguments: map [string ]interface {}{
726
- " query" : " john" ,
727
- " limit" : 5 ,
728
- },
729
- },
730
- })
731
- if err != nil {
732
- log.Fatal (err)
733
- }
734
-
735
- log.Printf (" Tool result: %+v " , result)
736
- }
737
- ```
738
-
739
- ### JavaScript/Fetch Client
740
-
741
- ``` javascript
742
- class MCPHTTPClient {
743
- constructor (baseURL , options = {}) {
744
- this .baseURL = baseURL;
745
- this .headers = {
746
- ' Content-Type' : ' application/json' ,
747
- ... options .headers
748
- };
749
- this .requestId = 1 ;
750
- }
751
-
752
- setAuthToken (token ) {
753
- this .headers [' Authorization' ] = ` Bearer ${ token} ` ;
754
- }
755
-
756
- async sendRequest (method , params = {}) {
757
- const id = this .requestId ++ ;
758
- const request = {
759
- jsonrpc: ' 2.0' ,
760
- id,
761
- method,
762
- params
763
- };
764
-
765
- const response = await fetch (` ${ this .baseURL } /${ method .replace (' /' , ' /' )} ` , {
766
- method: ' POST' ,
767
- headers: this .headers ,
768
- body: JSON .stringify (request)
769
- });
770
-
771
- if (! response .ok ) {
772
- throw new Error (` HTTP ${ response .status } : ${ response .statusText } ` );
773
- }
774
-
775
- const result = await response .json ();
776
-
777
- if (result .error ) {
778
- throw new Error (result .error .message );
779
- }
780
-
781
- return result .result ;
782
- }
783
-
784
- async initialize () {
785
- return this .sendRequest (' initialize' , {
786
- protocolVersion: ' 2024-11-05' ,
787
- capabilities: { tools: {} },
788
- clientInfo: { name: ' Web Client' , version: ' 1.0.0' }
789
- });
790
- }
791
-
792
- async listTools () {
793
- return this .sendRequest (' tools/list' );
794
- }
795
-
796
- async callTool (name , arguments ) {
797
- return this .sendRequest (' tools/call' , { name, arguments });
798
- }
799
-
800
- async listResources () {
801
- return this .sendRequest (' resources/list' );
802
- }
803
-
804
- async readResource (uri ) {
805
- return this .sendRequest (' resources/read' , { uri });
806
- }
807
- }
808
-
809
- // Usage
810
- const client = new MCPHTTPClient (' http://localhost:8080/mcp' );
811
- client .setAuthToken (' your-jwt-token' );
812
-
813
- async function main () {
814
- try {
815
- await client .initialize ();
816
-
817
- const tools = await client .listTools ();
818
- console .log (' Available tools:' , tools);
819
-
820
- const result = await client .callTool (' search_users' , {
821
- query: ' john' ,
822
- limit: 10
823
- });
824
- console .log (' Search result:' , result);
825
-
826
- } catch (error) {
827
- console .error (' Error:' , error);
828
- }
829
- }
830
-
831
- main ();
832
- ```
833
-
834
- ### cURL Examples
835
-
836
- ``` bash
837
- # Initialize session
838
- curl -X POST http://localhost:8080/mcp/initialize \
839
- -H " Content-Type: application/json" \
840
- -H " Authorization: Bearer your-token" \
841
- -d ' {
842
- "jsonrpc": "2.0",
843
- "id": 1,
844
- "method": "initialize",
845
- "params": {
846
- "protocolVersion": "2024-11-05",
847
- "capabilities": {"tools": {}},
848
- "clientInfo": {"name": "curl", "version": "1.0.0"}
849
- }
850
- }'
851
-
852
- # List tools
853
- curl -X POST http://localhost:8080/mcp/tools/list \
854
- -H " Content-Type: application/json" \
855
- -H " Authorization: Bearer your-token" \
856
- -d ' {
857
- "jsonrpc": "2.0",
858
- "id": 2,
859
- "method": "tools/list",
860
- "params": {}
861
- }'
862
-
863
- # Call tool
864
- curl -X POST http://localhost:8080/mcp/tools/call \
865
- -H " Content-Type: application/json" \
866
- -H " Authorization: Bearer your-token" \
867
- -d ' {
868
- "jsonrpc": "2.0",
869
- "id": 3,
870
- "method": "tools/call",
871
- "params": {
872
- "name": "search_users",
873
- "arguments": {
874
- "query": "john",
875
- "limit": 10
876
- }
877
- }
878
- }'
879
-
880
- # Read resource
881
- curl -X POST http://localhost:8080/mcp/resources/read \
882
- -H " Content-Type: application/json" \
883
- -H " Authorization: Bearer your-token" \
884
- -d ' {
885
- "jsonrpc": "2.0",
886
- "id": 4,
887
- "method": "resources/read",
888
- "params": {
889
- "uri": "users://123"
890
- }
891
- }'
892
- ```
893
-
894
- ## Performance and Scaling
895
-
896
- ### Load Balancing
897
-
898
- ``` go
899
- // Use with nginx or HAProxy
900
- upstream mcp_servers {
901
- server 127.0.0.1 :8080 ;
902
- server 127.0.0.1 :8081 ;
903
- server 127.0.0.1 :8082 ;
904
- }
905
-
906
- server {
907
- listen 80 ;
908
- server_name api.example .com ;
909
-
910
- location /mcp/ {
911
- proxy_pass http:// mcp_servers;
912
- proxy_set_header Host $host;
913
- proxy_set_header X-Real-IP $remote_addr;
914
- proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
915
- proxy_set_header X-Forwarded-Proto $scheme;
916
- }
917
- }
918
- ```
919
-
920
- ### Caching Strategies
921
-
922
- ``` go
923
- type CacheMiddleware struct {
924
- cache map [string ]cacheEntry
925
- mutex sync.RWMutex
926
- ttl time.Duration
927
- }
928
-
929
- type cacheEntry struct {
930
- data *mcp.ReadResourceResult
931
- timestamp time.Time
932
- etag string
933
- }
934
-
935
- func (m *CacheMiddleware ) ResourceMiddleware (next server .ResourceHandler ) server .ResourceHandler {
936
- return func (ctx context.Context , req mcp.ReadResourceRequest ) (*mcp.ReadResourceResult , error ) {
937
- // Check cache
938
- m.mutex .RLock ()
939
- entry , exists := m.cache [req.Params .URI ]
940
- m.mutex .RUnlock ()
941
-
942
- if exists && time.Since (entry.timestamp ) < m.ttl {
943
- // Add cache headers
944
- if httpCtx := getHTTPContext (ctx); httpCtx != nil {
945
- httpCtx.Header ().Set (" Cache-Control" , fmt.Sprintf (" max-age=%d " , int (m.ttl .Seconds ())))
946
- httpCtx.Header ().Set (" ETag" , entry.etag )
947
- }
948
- return entry.data , nil
949
- }
950
-
951
- // Fetch fresh data
952
- result , err := next (ctx, req)
953
- if err != nil {
954
- return nil , err
955
- }
956
-
957
- // Cache result
958
- etag := generateETag (result)
959
- m.mutex .Lock ()
960
- m.cache [req.Params .URI ] = cacheEntry{
961
- data: result,
962
- timestamp: time.Now (),
963
- etag: etag,
964
- }
965
- m.mutex .Unlock ()
966
-
967
- // Set cache headers
968
- if httpCtx := getHTTPContext (ctx); httpCtx != nil {
969
- httpCtx.Header ().Set (" Cache-Control" , fmt.Sprintf (" max-age=%d " , int (m.ttl .Seconds ())))
970
- httpCtx.Header ().Set (" ETag" , etag)
971
- }
972
-
973
- return result, nil
974
- }
975
- }
976
- ```
977
-
978
- ### Rate Limiting
979
-
980
- ``` go
981
- type RateLimiter struct {
982
- limiters map [string ]*rate.Limiter
983
- mutex sync.RWMutex
984
- rate rate.Limit
985
- burst int
986
- }
987
-
988
- func NewRateLimiter (requestsPerSecond float64 , burst int ) *RateLimiter {
989
- return &RateLimiter{
990
- limiters: make (map [string ]*rate.Limiter ),
991
- rate: rate.Limit (requestsPerSecond),
992
- burst: burst,
993
- }
994
- }
995
-
996
- func (rl *RateLimiter ) getLimiter (clientIP string ) *rate .Limiter {
997
- rl.mutex .RLock ()
998
- limiter , exists := rl.limiters [clientIP]
999
- rl.mutex .RUnlock ()
1000
-
1001
- if !exists {
1002
- rl.mutex .Lock ()
1003
- limiter = rate.NewLimiter (rl.rate , rl.burst )
1004
- rl.limiters [clientIP] = limiter
1005
- rl.mutex .Unlock ()
1006
- }
1007
-
1008
- return limiter
1009
- }
1010
-
1011
- func (rl *RateLimiter ) Allow (clientIP string ) bool {
1012
- return rl.getLimiter (clientIP).Allow ()
1013
- }
1014
-
1015
- // HTTP middleware
1016
- func (rl *RateLimiter ) Middleware (next http .Handler ) http .Handler {
1017
- return http.HandlerFunc (func (w http.ResponseWriter , r *http.Request ) {
1018
- clientIP := getClientIP (r)
1019
-
1020
- if !rl.Allow (clientIP) {
1021
- http.Error (w, " Rate limit exceeded" , http.StatusTooManyRequests )
1022
- return
1023
- }
1024
-
1025
- next.ServeHTTP (w, r)
1026
- })
1027
- }
1028
- ```
1029
682
1030
683
## Next Steps
1031
684
0 commit comments