@awarecorp/mcp-logger 0.0.8-dev.0 β 0.0.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +6 -20
- package/bin/mcp-logger.js +1 -1
- package/dist/cli/index.js +2 -0
- package/dist/index.d.ts +9 -55
- package/dist/index.js +1 -1
- package/package.json +1 -1
- package/dist/cli/interceptor.js +0 -1
- package/dist/cli/main.js +0 -2
- package/dist/cli/mcp-message-logger.js +0 -1
- package/dist/core/config.js +0 -1
- package/dist/core/span-builder.js +0 -1
- package/dist/core/span-utils.js +0 -1
- package/dist/core/telemetry.js +0 -1
- package/dist/core/types.d.ts +0 -228
- package/dist/sdk/index.js +0 -1
- package/dist/sdk/instrumentation.js +0 -1
- package/dist/sdk/types.d.ts +0 -91
package/README.md
CHANGED
|
@@ -46,8 +46,7 @@ Wrap any existing MCP server without code changes:
|
|
|
46
46
|
```bash
|
|
47
47
|
npx @awarecorp/mcp-logger \
|
|
48
48
|
-k YOUR_API_KEY \
|
|
49
|
-
|
|
50
|
-
npx your-mcp-server
|
|
49
|
+
-- npx your-mcp-server
|
|
51
50
|
```
|
|
52
51
|
|
|
53
52
|
## π Features
|
|
@@ -87,7 +86,8 @@ Optimized for Elasticsearch with flat structure:
|
|
|
87
86
|
- `mcp.request.params` / `mcp.response.result`: Request/response payloads
|
|
88
87
|
- `mcp.error.message`: Enhanced error serialization (no more `[object Object]`)
|
|
89
88
|
- `mcp.events`: Custom log entries (JSON array)
|
|
90
|
-
- `mcp.
|
|
89
|
+
- `mcp.sdk.name`: MCP SDK/framework name (e.g., `FastMCP`)
|
|
90
|
+
- `mcp.sdk.version`: MCP SDK/framework version
|
|
91
91
|
|
|
92
92
|
## π§ SDK API
|
|
93
93
|
|
|
@@ -99,13 +99,8 @@ Enable automatic instrumentation on an MCP server.
|
|
|
99
99
|
|
|
100
100
|
- `server`: MCP Server instance
|
|
101
101
|
- `options.apiKey`: API key for authentication (required)
|
|
102
|
-
- Currently accepts any string value for testing purposes
|
|
103
|
-
- For production use, sign up at [Aware](https://awarecorp.io/) to get your API key
|
|
104
102
|
- `options.serviceName`: Service identifier (optional, auto-generated if omitted)
|
|
105
|
-
- `options.endpoint`: Custom OTLP endpoint (optional
|
|
106
|
-
- Accepts any OTLP/HTTP compatible endpoint URL
|
|
107
|
-
- Use this to send traces to your own observability backend (e.g., Jaeger, Grafana, etc.)
|
|
108
|
-
- `options.debug`: Enable debug logging (optional, default: false)
|
|
103
|
+
- `options.endpoint`: Custom OTLP endpoint (optional)
|
|
109
104
|
|
|
110
105
|
**Returns:** `void`
|
|
111
106
|
|
|
@@ -139,21 +134,14 @@ mcp-logger [options] <command...>
|
|
|
139
134
|
### Options
|
|
140
135
|
|
|
141
136
|
- `-k, --api-key <key>`: API key (required)
|
|
142
|
-
|
|
143
|
-
- Sign up at [Aware](https://awarecorp.io/) to get your API key for production use
|
|
144
|
-
- `-s, --service-name <name>`: Service name (optional)
|
|
145
|
-
- `-e, --endpoint <url>`: Custom OTLP endpoint (optional, default: `https://aware.mcypher.com/v1/traces`)
|
|
146
|
-
- Send traces to any OTLP/HTTP compatible backend
|
|
147
|
-
- Examples: Jaeger, Grafana Tempo, New Relic, Honeycomb, etc.
|
|
148
|
-
- `-d, --debug`: Enable debug logging (optional)
|
|
149
|
-
- Shows detailed information about message processing and span creation
|
|
137
|
+
- `-e, --endpoint <url>`: Custom OTLP endpoint (optional)
|
|
150
138
|
|
|
151
139
|
### Examples
|
|
152
140
|
|
|
153
141
|
**Wrap an npx command:**
|
|
154
142
|
|
|
155
143
|
```bash
|
|
156
|
-
mcp-logger -k API_KEY
|
|
144
|
+
mcp-logger -k API_KEY -- npx -y @modelcontextprotocol/server-filesystem /path
|
|
157
145
|
```
|
|
158
146
|
|
|
159
147
|
**Use with Claude Desktop:**
|
|
@@ -168,8 +156,6 @@ mcp-logger -k API_KEY -s filesystem npx -y @modelcontextprotocol/server-filesyst
|
|
|
168
156
|
"@awarecorp/mcp-logger",
|
|
169
157
|
"-k",
|
|
170
158
|
"YOUR_API_KEY",
|
|
171
|
-
"-s",
|
|
172
|
-
"my-server",
|
|
173
159
|
"--",
|
|
174
160
|
"npx",
|
|
175
161
|
"-y",
|
package/bin/mcp-logger.js
CHANGED
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
function e(...e){console.error("[mcp-logger]",...e)}function s(...e){N&&console.error("[mcp-logger]",...e)}function t(...e){x&&console.error("[mcp-logger]",...e)}function r(e){return!M.includes(e)}function n(){return A.getTracer()}function o(){return A.getCLIServerInfo()}async function i(){await A.shutdown()}function c(e,s){for(const[t,r]of Object.entries(s))null!=r&&e.setAttribute(t,r)}function a(e,s=2e5){try{const t=JSON.stringify(e);return t.length>s?t.slice(0,s)+"... (truncated)":t}catch{return null}}function p(e,s){return e.startsWith("resources/")?{type:e.split("/")[1],uri:s?.uri||s?.path||s?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:s?.name||s?.promptId}:"tools/call"===e?{type:"tool",uri:s?.name}:s?.resourceType&&s?.resourceUri?{type:s.resourceType,uri:s.resourceUri}:{type:void 0,uri:void 0}}function m(e,s,t,r,n){const o=function(e,s){const t=e?.getClientInfo();if(t?.name||t?.version)return{name:t.name,version:t.version};const r=e?.getHeaders()||s;if(r){const e=r["user-agent"]||r["User-Agent"];if(e){const s=e.match(/^([^\/]+)\/([^\s]+)/);if(s)return{name:s[1],version:s[2]}}}return{name:void 0,version:void 0}}(r,n),i=`${o.name||"unknown"}-${o.version||"0"}`,c=T.getOrCreateSessionId(i),a=T.getOrCreateConversationId(c,e),m=function(e,s){return e?.userId||e?.user_id?e.userId||e.user_id:s?s["x-user-id"]||s["X-User-Id"]:void 0}(s,n),u=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(s),d=p(e,s);d.uri&&T.trackResourceAccess(d.uri);const l=function(e,s){return void 0!==e?.cost?e.cost:void 0!==s?.cost?s.cost:void 0}(s,t),h={};return c&&(h.sessionId=c),a&&(h.conversationId=a),m&&(h.userId=m),o.name&&(h.clientName=o.name),o.version&&(h.clientVersion=o.version),u&&(h.permissionLevel=u),void 0!==l&&(h.cost=l),h}function u(e,s){const t=p(e,s);if(!t.uri)return{};const r=T.getResourceAccessCount(t.uri);return{resourceType:t.type,resourceUri:t.uri,resourceAccessCount:r}}import{execSync as d,spawn as l}from"child_process";import{program as h}from"commander";import{NodeSDK as f}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as v}from"@opentelemetry/exporter-trace-otlp-http";import{Resource as g}from"@opentelemetry/resources";import{trace as I,SpanStatusCode as S}from"@opentelemetry/api";import{readFileSync as y}from"fs";import{fileURLToPath as q}from"url";import{dirname as w,join as C}from"path";import{Transform as R}from"stream";import{ulid as E}from"ulid";const N="true"===process.env.AWARE_DEBUG||"1"===process.env.AWARE_DEBUG,x="true"===process.env.AWARE_RAW_DEBUG||"1"===process.env.AWARE_RAW_DEBUG,O={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const e=q(import.meta.url),s=w(e),t=C(s,"..","..","package.json");return JSON.parse(y(t,"utf-8")).version||"1.0.0"}catch{return"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"},M=["notifications/initialized"],A=new class{sdk=null;tracer=null;initialized=!1;cliServerInfo=null;initialize(e){if(this.initialized)return s("Telemetry already initialized, returning existing tracer"),this.tracer;const t=e.endpoint||O.ENDPOINT,r=e.serviceName||`${O.SERVICE_NAME_PREFIX}-${Math.random().toString(36).slice(2,8)}`,n=e.serviceVersion||"unknown";s("Initializing telemetry..."),s("Endpoint: "+t),s("Service: "+r),s("Version: "+n),this.sdk=new f({resource:new g({"service.name":r,"service.version":n}),traceExporter:new v({url:t,headers:{"x-api-key":e.apiKey}})}),this.sdk.start(),this.tracer=I.getTracer("mcp-logger",O.SDK_VERSION),this.initialized=!0,s("Telemetry initialized successfully");const o=async()=>{s("Shutting down telemetry..."),await this.shutdown()};return process.once("SIGTERM",o),process.once("SIGINT",o),this.tracer}getTracer(){return this.tracer}isInitialized(){return this.initialized}setCLIServerInfo(e,s,t){this.cliServerInfo={command:e,args:s,env:t}}getCLIServerInfo(){return this.cliServerInfo}async shutdown(){if(this.sdk)try{await this.sdk.shutdown(),this.sdk=null,this.tracer=null,this.initialized=!1,this.cliServerInfo=null}catch(e){console.error("[mcp-logger] Error shutting down telemetry:",e)}}};class k extends R{buffer="";direction;logger;sessionContextStore;constructor(e,s,t){super(),this.direction=e,this.logger=s,this.sessionContextStore=t}_transform(e,t,r){try{if("request"===this.direction)return this.push(e),this.buffer+=e.toString(),this.tryParseMessages(),void r();this.buffer+=e.toString(),this.buffer.length>1e6&&(s("Buffer size exceeded, clearing..."),this.buffer=""),this.tryParseAndForwardMessages(),r()}catch(e){r(e)}}tryParseMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const r of e){const e=r.trim();if(e)try{const s=JSON.parse(e);t(`[${this.direction}] Raw message:`,e),this.handleMessage(s)}catch{s("Failed to parse:",e.slice(0,100))}}}tryParseAndForwardMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const r of e){const e=r.trim();if(e)try{const r=JSON.parse(e);"2.0"===r.jsonrpc?(this.push(e+"\n"),t(`[${this.direction}] Raw message:`,e),this.handleMessage(r)):s("Non-JSON-RPC JSON ignored:",e.slice(0,100))}catch{s("Non-JSON output filtered:",e.slice(0,100))}}}isValidInfo(e){return!(!e?.name||!e?.version)}handleMessage(e){if("request"===this.direction&&"initialize"===e.method&&e.params?.clientInfo&&!this.isValidInfo(this.sessionContextStore.getClientInfo())){const s=e.params;this.sessionContextStore.setClientInfo({name:s.clientInfo?.name,version:s.clientInfo?.version})}if("response"===this.direction&&void 0!==e.id&&!e.method){const s=e;if(s.result?.serverInfo&&!this.isValidInfo(this.sessionContextStore.getServerInfo())){const e=s.result.serverInfo;this.sessionContextStore.setServerInfo({name:e.name,version:e.version})}}"request"===this.direction&&e.method?this.logger.onRequest(e):"response"===this.direction&&(void 0===e.id||e.method?e.method&&!e.id&&this.logger.onNotification(e):this.logger.onResponse(e))}_flush(e){try{if(this.buffer.trim())try{const e=JSON.parse(this.buffer);"response"===this.direction&&"2.0"===e.jsonrpc&&this.push(this.buffer.trim()+"\n"),this.handleMessage(e)}catch{"request"===this.direction&&this.push(this.buffer),s("Failed to parse final buffer")}N&&s("Stream closed. Pending requests: "+this.logger.getStats().pending),e()}catch(s){e(s)}}}const T=new class{sessionMap=new Map;sessionCounter=0;conversationMap=new Map;conversationCounter=0;resourceAccessCount=new Map;getOrCreateSessionId(e){if(!this.sessionMap.has(e)){const s=E();this.sessionMap.set(e,s),this.sessionCounter++}return this.sessionMap.get(e)}getOrCreateConversationId(e,s){const t=`${e}-${s}`;return this.conversationMap.has(t)||this.conversationMap.set(t,"conv-"+ ++this.conversationCounter),this.conversationMap.get(t)}trackResourceAccess(e){const s=(this.resourceAccessCount.get(e)||0)+1;return this.resourceAccessCount.set(e,s),s}getResourceAccessCount(e){return this.resourceAccessCount.get(e)||0}clear(){this.sessionMap.clear(),this.conversationMap.clear(),this.resourceAccessCount.clear(),this.sessionCounter=0,this.conversationCounter=0}};class ${pendingRequests=new Map;TIMEOUT=3e4;sessionContextStore;constructor(e){this.sessionContextStore=e}onRequest(e){r(e.method)&&(e.id?(this.pendingRequests.set(e.id,{request:e,timestamp:Date.now()}),"initialize"===e.method&&e.params?.clientInfo&&this.sessionContextStore.setClientInfo({name:e.params.clientInfo.name,version:e.params.clientInfo.version}),setTimeout(()=>this.cleanupStale(e.id),this.TIMEOUT)):this.createRequestOnlySpan(e,Date.now()))}onResponse(e){if(!e.id)return;const s=this.pendingRequests.get(e.id);if(!s)return void this.createResponseOnlySpan(e,Date.now());const t=Date.now(),r=t-s.timestamp;this.createPairedSpan(s.request,e,s.timestamp,t,r),this.pendingRequests.delete(e.id)}onNotification(e){r(e.method)&&this.createResponseOnlySpan({jsonrpc:"2.0",id:`notification-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,method:e.method},Date.now())}createPairedSpan(e,s,r,i,p){const d=m(e.method,e.params,s.result,this.sessionContextStore,void 0);let l=this.sessionContextStore.getServerInfo();"initialize"===e.method&&s.result?.serverInfo&&(l={name:s.result.serverInfo.name,version:s.result.serverInfo.version}),function(e){const s=n();if(!s)return;const r="mcp."+e.method;s.startActiveSpan(r,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.request.id":e.request.id+"","mcp.request.method":e.method,"mcp.request.timestamp":e.request.timestamp,"mcp.request.params":a(e.request.params)||"{}","mcp.request.params.size":JSON.stringify(e.request.params||{}).length,"mcp.response.id":e.request.id+"","mcp.response.timestamp":e.response.timestamp,"mcp.duration_ms":e.duration};if("tools/call"===e.method&&e.request.params){const s=e.request.params.name,t=e.request.params.arguments;if(s&&(r["mcp.tool.name"]=s),t){const e=a(t);e&&(r["mcp.tool.arguments"]=e,r["mcp.tool.arguments.size"]=JSON.stringify(t).length)}}if(void 0!==e.response.result){const s=a(e.response.result);s&&(r["mcp.response.result"]=s,r["mcp.response.result.size"]=JSON.stringify(e.response.result).length)}if(e.request.headers){const s=a(e.request.headers);s&&(r["mcp.headers"]=s,r["mcp.headers.size"]=JSON.stringify(e.request.headers).length)}if("cli"===e.source){const e=o();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}))}e.serverInfo&&(e.serverInfo.name&&(r["mcp.sdk.name"]=e.serverInfo.name),e.serverInfo.version&&(r["mcp.sdk.version"]=e.serverInfo.version));const n=e.contextMetadata||m(e.method,e.request.params,e.response.result,void 0,e.request.headers);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost);const i=u(e.method,e.request.params);if(i.resourceType&&(r["mcp.resource.type"]=i.resourceType),i.resourceUri&&(r["mcp.resource.uri"]=i.resourceUri),i.resourceAccessCount&&(r["mcp.resource.access_count"]=i.resourceAccessCount),e.customEvents&&e.customEvents.length>0&&(r["mcp.events"]=JSON.stringify(e.customEvents),r["mcp.events.count"]=e.customEvents.length,e.customEvents.forEach(e=>{s.addEvent("custom."+(e.level||"info"),{message:e.message,metadata:JSON.stringify(e.metadata||{}),timestamp:e.timestamp||Date.now()})})),e.response.error){let t;r["mcp.error"]=!0,t=e.response.error instanceof Error?e.response.error.message:"string"==typeof e.response.error?e.response.error:a(e.response.error)||"Unknown error",r["mcp.error.message"]=t,e.response.error instanceof Error&&s.recordException(e.response.error),s.setStatus({code:S.ERROR,message:t})}else s.setStatus({code:S.OK});c(s,r),t("[OTLP] Span data:",JSON.stringify(r,null,2))}catch{s.setStatus({code:S.ERROR,message:"Error creating span"})}finally{s.end()}})}({method:e.method,source:"cli",transport:"stdio",request:{id:e.id,timestamp:r,params:e.params},response:{timestamp:i,result:s.result,error:s.error},duration:p,contextMetadata:d,serverInfo:l})}cleanupStale(e){const s=this.pendingRequests.get(e);s&&Date.now()-s.timestamp>this.TIMEOUT&&(this.createRequestOnlySpan(s.request,s.timestamp),this.pendingRequests.delete(e))}createRequestOnlySpan(e,s){const r=m(e.method,e.params,void 0,this.sessionContextStore,void 0);!function(e){const s=n();if(!s)return;const r="mcp."+e.method;s.startActiveSpan(r,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.request.id":e.request.id+"","mcp.request.method":e.method,"mcp.request.timestamp":e.request.timestamp,"mcp.request.params":a(e.request.params)||"{}","mcp.request.params.size":JSON.stringify(e.request.params||{}).length};if("tools/call"===e.method&&e.request.params){const s=e.request.params.name,t=e.request.params.arguments;if(s&&(r["mcp.tool.name"]=s),t){const e=a(t);e&&(r["mcp.tool.arguments"]=e,r["mcp.tool.arguments.size"]=JSON.stringify(t).length)}}if("cli"===e.source){const e=o();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}))}e.serverInfo&&(e.serverInfo.name&&(r["mcp.sdk.name"]=e.serverInfo.name),e.serverInfo.version&&(r["mcp.sdk.version"]=e.serverInfo.version));const n=e.contextMetadata||m(e.method,e.request.params,void 0,void 0,e.request.headers);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost);const i=u(e.method,e.request.params);i.resourceType&&(r["mcp.resource.type"]=i.resourceType),i.resourceUri&&(r["mcp.resource.uri"]=i.resourceUri),i.resourceAccessCount&&(r["mcp.resource.access_count"]=i.resourceAccessCount),s.setStatus({code:S.OK}),c(s,r),t("[OTLP] Span data:",JSON.stringify(r,null,2))}catch{s.setStatus({code:S.ERROR,message:"Error creating span"})}finally{s.end()}})}({method:e.method,source:"cli",transport:"stdio",request:{id:e.id,timestamp:s,params:e.params},contextMetadata:r})}createResponseOnlySpan(e,s){const r=m(e.method||"unknown",void 0,e.result,this.sessionContextStore,void 0),i=this.sessionContextStore.getServerInfo();!function(e){const s=n();if(!s)return;const r="mcp."+e.method;s.startActiveSpan(r,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.response.id":e.response.id+"","mcp.response.method":e.method,"mcp.response.timestamp":e.response.timestamp};if(void 0!==e.response.result){const s=a(e.response.result);s&&(r["mcp.response.result"]=s,r["mcp.response.result.size"]=JSON.stringify(e.response.result).length)}if(e.response.error){let t;r["mcp.error"]=!0,t=e.response.error instanceof Error?e.response.error.message:"string"==typeof e.response.error?e.response.error:a(e.response.error)||"Unknown error",r["mcp.error.message"]=t,e.response.error instanceof Error&&s.recordException(e.response.error),s.setStatus({code:S.ERROR,message:t})}else s.setStatus({code:S.OK});if("cli"===e.source){const e=o();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}))}e.serverInfo&&(e.serverInfo.name&&(r["mcp.sdk.name"]=e.serverInfo.name),e.serverInfo.version&&(r["mcp.sdk.version"]=e.serverInfo.version));const n=e.contextMetadata||m(e.method,void 0,e.response.result,void 0,void 0);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost),c(s,r),t("[OTLP] Span data:",JSON.stringify(r,null,2))}catch{s.setStatus({code:S.ERROR,message:"Error creating span"})}finally{s.end()}})}({method:e.method||"same_request_method",source:"cli",transport:"stdio",response:{id:e.id,timestamp:s,result:e.result,error:e.error},contextMetadata:r,serverInfo:i})}getStats(){return{pending:this.pendingRequests.size}}clear(){this.pendingRequests.clear()}}class P{context={};getClientInfo(){return this.context.clientInfo}setClientInfo(e){this.context.clientInfo=e}getServerInfo(){return this.context.serverInfo}setServerInfo(e){this.context.serverInfo=e}getHeaders(){return this.context.headers}setHeaders(e){this.context.headers=e}snapshot(){return{clientInfo:this.context.clientInfo?{...this.context.clientInfo}:void 0,serverInfo:this.context.serverInfo?{...this.context.serverInfo}:void 0,headers:this.context.headers?{...this.context.headers}:void 0}}}const _=new Set(["npx","node","uvx","python","python3","pip","pipx","deno","bun"]),z=new Set(["uvx","python","python3","pip","pipx"]);h.name("mcp-logger").description("Add observability to any MCP server without code changes").version("1.0.0").requiredOption("-k, --api-key <key>","Aware API key").option("-e, --endpoint <url>","Custom OTLP endpoint").argument("<command...>","MCP server command to wrap").action(async(t,r)=>{try{const n=function(e){const s={};for(const t of e){const e=process.env[t];void 0!==e&&(s[t]=e)}return s}(function(){try{return d("aware mcpenv sync",{encoding:"utf-8",timeout:1e4,stdio:["pipe","pipe","pipe"]}),d("aware mcpenv keys",{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim().split("\n").filter(e=>e.length>0)}catch{return[]}}()),[o,...c]=t,a=function(e,s){const t=function(e){for(const s of e){if(_.has(s))continue;const e=s.match(/^(@[^@]+\/[^@]+)@(.+)$/);if(e)return{packageName:e[1],version:e[2]};const t=s.match(/^([^@]+)@(.+)$/);if(t)return{packageName:t[1],version:t[2]};const r=s.match(/^(@[^@]+\/[^@]+)$/);if(r)return{packageName:r[1],version:"latest"};if(s.match(/^[a-z0-9-]+$/)&&!s.includes("/"))return{packageName:s,version:"latest"}}return null}(s.filter(e=>!e.startsWith("-")));let r,n;if(r=t?.packageName?t.packageName:e.split("/").pop()||e||O.SERVICE_NAME_PREFIX+"-unknown",t&&(n=t.version,"latest"===t.version)){const s=z.has(e)?"pip":"npm",r=function(e,s){try{if("pip"===s){let s=null;for(const t of["pip3","pip"])try{s=d(`${t} index versions ${e}`,{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]});break}catch{continue}if(!s)return null;const t=s.match(/\(([^)]+)\)/);if(t)return t[1];const r=s.match(/Available versions:\s*([^\s,]+)/);return r?r[1]:null}{const s=d(`npm view ${e} version --json`,{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim().replace(/^["']|["']$/g,""),t=s.match(/^(\d+\.\d+\.\d+(?:-[\w.]+)?)/);return t?t[1]:s}}catch{return null}}(t.packageName,s);r&&(n=r)}return{name:r,version:n}}(o,c);!function(e){A.initialize(e)}({...r,serviceName:a.name,serviceVersion:a.version}),e("Starting MCP server: "+t.join(" ")),e(`Service: ${a.name} = ${a.version||"unknown"}`),function(e,s,t){A.setCLIServerInfo(e,s,t)}(o,c,n);const p=l(o,c,{stdio:["pipe","pipe","inherit"],env:{...process.env,MCP_LOGGER_ENABLED:"true"}}),m=new P,u=new $(m),h=new k("request",u,m);process.stdin.pipe(h).pipe(p.stdin);const f=new k("response",u,m);p.stdout.pipe(f).pipe(process.stdout),p.on("error",async s=>{e("Failed to start MCP server:",s),u.clear(),await i(),process.exit(1)}),p.on("exit",async(e,t)=>{s(`MCP server exited with code ${e}, signal ${t}`),u.clear(),await i(),process.exit(e||0)});let v=!1;const g=async e=>{v||(v=!0,s(`Received ${e}, shutting down...`),p.kill(e),await Promise.race([new Promise(e=>p.once("exit",e)),new Promise(e=>setTimeout(e,5e3))]),await i(),process.exit(0))};process.on("SIGTERM",()=>g("SIGTERM")),process.on("SIGINT",()=>g("SIGINT"))}catch(s){e("Fatal error:",s),await i(),process.exit(1)}}),h.parse();
|
package/dist/index.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
2
|
|
|
3
3
|
/**
|
|
4
|
-
*
|
|
4
|
+
* μΈμ
λ° ν
λ λ©νΈλ¦¬ κ΄λ ¨ νμ
μ μ
|
|
5
5
|
*/
|
|
6
6
|
/**
|
|
7
7
|
* ν
λ λ©νΈλ¦¬ μ΄κΈ°ν μ΅μ
|
|
@@ -16,20 +16,21 @@ interface TelemetryOptions {
|
|
|
16
16
|
* μ§μ νμ§ μμΌλ©΄ μλμΌλ‘ 'mcp-server-{random}' νμμΌλ‘ μμ±
|
|
17
17
|
*/
|
|
18
18
|
serviceName?: string;
|
|
19
|
+
/**
|
|
20
|
+
* μλΉμ€ λ²μ (μ΅μ
)
|
|
21
|
+
* MCP μλ²μ λ²μ . μ§μ νμ§ μμΌλ©΄ 'unknown'
|
|
22
|
+
*/
|
|
23
|
+
serviceVersion?: string;
|
|
19
24
|
/**
|
|
20
25
|
* 컀μ€ν
OTLP μλν¬μΈνΈ (μ΅μ
)
|
|
21
26
|
* κΈ°λ³Έκ°: CONFIG.ENDPOINT
|
|
22
27
|
*/
|
|
23
28
|
endpoint?: string;
|
|
24
|
-
/**
|
|
25
|
-
* λλ²κ·Έ λ‘κ·Έ νμ±ν (μ΅μ
)
|
|
26
|
-
*/
|
|
27
|
-
debug?: boolean;
|
|
28
29
|
}
|
|
29
30
|
/**
|
|
30
31
|
* 컀μ€ν
λ‘κ·Έ μνΈλ¦¬
|
|
31
32
|
*/
|
|
32
|
-
interface CustomLogEntry
|
|
33
|
+
interface CustomLogEntry {
|
|
33
34
|
/**
|
|
34
35
|
* λ‘κ·Έ λ 벨
|
|
35
36
|
*/
|
|
@@ -57,10 +58,7 @@ interface CustomLogEntry$1 {
|
|
|
57
58
|
*/
|
|
58
59
|
interface TraceOptions extends TelemetryOptions {
|
|
59
60
|
}
|
|
60
|
-
|
|
61
|
-
* Custom Log Entry (re-export from core)
|
|
62
|
-
*/
|
|
63
|
-
type CustomLogEntry = CustomLogEntry$1;
|
|
61
|
+
|
|
64
62
|
/**
|
|
65
63
|
* MCP Server νμ
(μ¬export)
|
|
66
64
|
*/
|
|
@@ -74,60 +72,16 @@ type MCPServer = Server;
|
|
|
74
72
|
|
|
75
73
|
/**
|
|
76
74
|
* trace λ€μμ€νμ΄μ€
|
|
77
|
-
*
|
|
78
|
-
* @example
|
|
79
|
-
* ```typescript
|
|
80
|
-
* import { trace } from '@awarecorp/mcp-logger';
|
|
81
|
-
*
|
|
82
|
-
* // μλ² κ³μΈ‘
|
|
83
|
-
* trace(server, {
|
|
84
|
-
* apiKey: 'your-api-key',
|
|
85
|
-
* serviceName: 'my-service',
|
|
86
|
-
* });
|
|
87
|
-
*
|
|
88
|
-
* // Handler λ΄λΆμμ 컀μ€ν
λ‘κ·Έ μΆκ°
|
|
89
|
-
* server.setRequestHandler('tools/call', async (request) => {
|
|
90
|
-
* trace.addLog({
|
|
91
|
-
* level: 'info',
|
|
92
|
-
* message: 'Processing started',
|
|
93
|
-
* metadata: { id: request.params.arguments.id },
|
|
94
|
-
* });
|
|
95
|
-
*
|
|
96
|
-
* const result = await process();
|
|
97
|
-
*
|
|
98
|
-
* trace.addLog({
|
|
99
|
-
* level: 'info',
|
|
100
|
-
* message: 'Processing completed',
|
|
101
|
-
* metadata: { duration: 100 },
|
|
102
|
-
* });
|
|
103
|
-
*
|
|
104
|
-
* return result;
|
|
105
|
-
* });
|
|
106
|
-
* ```
|
|
107
75
|
*/
|
|
108
76
|
declare const trace: ((server: MCPServer, options: TraceOptions) => void) & {
|
|
109
77
|
/**
|
|
110
78
|
* νμ¬ active spanμ 컀μ€ν
λ‘κ·Έ μΆκ°
|
|
111
79
|
*
|
|
112
80
|
* β οΈ μ£Όμ: Request handler λ΄λΆμμλ§ νΈμΆν΄μΌ ν©λλ€.
|
|
113
|
-
*
|
|
114
|
-
* @param entry - 컀μ€ν
λ‘κ·Έ μνΈλ¦¬
|
|
115
|
-
*
|
|
116
|
-
* @example
|
|
117
|
-
* ```typescript
|
|
118
|
-
* trace.addLog({
|
|
119
|
-
* level: 'info',
|
|
120
|
-
* message: 'Database query executed',
|
|
121
|
-
* metadata: { query: 'SELECT * FROM users', rows: 42 },
|
|
122
|
-
* });
|
|
123
|
-
* ```
|
|
124
81
|
*/
|
|
125
|
-
addLog(entry: CustomLogEntry
|
|
82
|
+
addLog(entry: CustomLogEntry): void;
|
|
126
83
|
/**
|
|
127
84
|
* Telemetry μ’
λ£
|
|
128
|
-
*
|
|
129
|
-
* μΌλ°μ μΌλ‘ λͺ
μμ μΌλ‘ νΈμΆν νμλ μμ΅λλ€.
|
|
130
|
-
* νλ‘μΈμ€ μ’
λ£ μ μλμΌλ‘ μ²λ¦¬λ©λλ€.
|
|
131
85
|
*/
|
|
132
86
|
shutdown(): Promise<void>;
|
|
133
87
|
};
|
package/dist/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
function e(
|
|
1
|
+
function e(...e){g&&console.error("[mcp-logger]",...e)}function s(e,s=2e5){try{const t=JSON.stringify(e);return t.length>s?t.slice(0,s)+"... (truncated)":t}catch{return null}}function t(e,s){return e.startsWith("resources/")?{type:e.split("/")[1],uri:s?.uri||s?.path||s?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:s?.name||s?.promptId}:"tools/call"===e?{type:"tool",uri:s?.name}:s?.resourceType&&s?.resourceUri?{type:s.resourceType,uri:s.resourceUri}:{type:void 0,uri:void 0}}function r(e,s,r,n,o){const i=function(e,s){const t=s;if(t){const e=t["user-agent"]||t["User-Agent"];if(e){const s=e.match(/^([^\/]+)\/([^\s]+)/);if(s)return{name:s[1],version:s[2]}}}return{name:void 0,version:void 0}}(0,o),c=`${i.name||"unknown"}-${i.version||"0"}`,a=E.getOrCreateSessionId(c),u=E.getOrCreateConversationId(a,e),m=function(e,s){return e?.userId||e?.user_id?e.userId||e.user_id:s?s["x-user-id"]||s["X-User-Id"]:void 0}(s,o),p=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(s),d=t(e,s);d.uri&&E.trackResourceAccess(d.uri);const l=function(e,s){return void 0!==e?.cost?e.cost:void 0!==s?.cost?s.cost:void 0}(s,r),v={};return a&&(v.sessionId=a),u&&(v.conversationId=u),m&&(v.userId=m),i.name&&(v.clientName=i.name),i.version&&(v.clientVersion=i.version),p&&(v.permissionLevel=p),void 0!==l&&(v.cost=l),v}function n(e){const n=I.getTracer();if(!n)return;const o="mcp."+e.method;n.startActiveSpan(o,n=>{try{const o={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.request.id":e.request.id+"","mcp.request.method":e.method,"mcp.request.timestamp":e.request.timestamp,"mcp.request.params":s(e.request.params)||"{}","mcp.request.params.size":JSON.stringify(e.request.params||{}).length,"mcp.response.id":e.request.id+"","mcp.response.timestamp":e.response.timestamp,"mcp.duration_ms":e.duration};if("tools/call"===e.method&&e.request.params){const t=e.request.params.name,r=e.request.params.arguments;if(t&&(o["mcp.tool.name"]=t),r){const e=s(r);e&&(o["mcp.tool.arguments"]=e,o["mcp.tool.arguments.size"]=JSON.stringify(r).length)}}if(void 0!==e.response.result){const t=s(e.response.result);t&&(o["mcp.response.result"]=t,o["mcp.response.result.size"]=JSON.stringify(e.response.result).length)}if(e.request.headers){const t=s(e.request.headers);t&&(o["mcp.headers"]=t,o["mcp.headers.size"]=JSON.stringify(e.request.headers).length)}if("cli"===e.source){const e=I.getCLIServerInfo();e&&(o["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}))}e.serverInfo&&(e.serverInfo.name&&(o["mcp.sdk.name"]=e.serverInfo.name),e.serverInfo.version&&(o["mcp.sdk.version"]=e.serverInfo.version));const c=e.contextMetadata||r(e.method,e.request.params,e.response.result,0,e.request.headers);c.sessionId&&(o["mcp.session.id"]=c.sessionId),c.conversationId&&(o["mcp.conversation.id"]=c.conversationId),c.sessionId&&c.conversationId&&(o["mcp.trace.id"]=`${c.sessionId}:${c.conversationId}`),c.userId&&(o["mcp.user.id"]=c.userId),c.clientName&&(o["mcp.client.name"]=c.clientName),c.clientVersion&&(o["mcp.client.version"]=c.clientVersion),c.permissionLevel&&(o["mcp.permission.level"]=c.permissionLevel),void 0!==c.cost&&(o["mcp.cost"]=c.cost);const a=function(e,s){const r=t(e,s);if(!r.uri)return{};const n=E.getResourceAccessCount(r.uri);return{resourceType:r.type,resourceUri:r.uri,resourceAccessCount:n}}(e.method,e.request.params);if(a.resourceType&&(o["mcp.resource.type"]=a.resourceType),a.resourceUri&&(o["mcp.resource.uri"]=a.resourceUri),a.resourceAccessCount&&(o["mcp.resource.access_count"]=a.resourceAccessCount),e.customEvents&&e.customEvents.length>0&&(o["mcp.events"]=JSON.stringify(e.customEvents),o["mcp.events.count"]=e.customEvents.length,e.customEvents.forEach(e=>{n.addEvent("custom."+(e.level||"info"),{message:e.message,metadata:JSON.stringify(e.metadata||{}),timestamp:e.timestamp||Date.now()})})),e.response.error){let t;o["mcp.error"]=!0,t=e.response.error instanceof Error?e.response.error.message:"string"==typeof e.response.error?e.response.error:s(e.response.error)||"Unknown error",o["mcp.error.message"]=t,e.response.error instanceof Error&&n.recordException(e.response.error),n.setStatus({code:i.ERROR,message:t})}else n.setStatus({code:i.OK});!function(e,s){for(const[t,r]of Object.entries(s))null!=r&&e.setAttribute(t,r)}(n,o),function(...e){f&&console.error("[mcp-logger]",...e)}("[OTLP] Span data:",JSON.stringify(o,null,2))}catch{n.setStatus({code:i.ERROR,message:"Error creating span"})}finally{n.end()}})}import{trace as o,SpanStatusCode as i,context as c}from"@opentelemetry/api";import{NodeSDK as a}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as u}from"@opentelemetry/exporter-trace-otlp-http";import{Resource as m}from"@opentelemetry/resources";import{readFileSync as p}from"fs";import{fileURLToPath as d}from"url";import{dirname as l,join as v}from"path";import{ulid as h}from"ulid";const g="true"===process.env.AWARE_DEBUG||"1"===process.env.AWARE_DEBUG,f="true"===process.env.AWARE_RAW_DEBUG||"1"===process.env.AWARE_RAW_DEBUG,y={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const e=d(import.meta.url),s=l(e),t=v(s,"..","..","package.json");return JSON.parse(p(t,"utf-8")).version||"1.0.0"}catch{return"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"},I=new class{sdk=null;tracer=null;initialized=!1;cliServerInfo=null;initialize(s){if(this.initialized)return e("Telemetry already initialized, returning existing tracer"),this.tracer;const t=s.endpoint||y.ENDPOINT,r=s.serviceName||`${y.SERVICE_NAME_PREFIX}-${Math.random().toString(36).slice(2,8)}`,n=s.serviceVersion||"unknown";e("Initializing telemetry..."),e("Endpoint: "+t),e("Service: "+r),e("Version: "+n),this.sdk=new a({resource:new m({"service.name":r,"service.version":n}),traceExporter:new u({url:t,headers:{"x-api-key":s.apiKey}})}),this.sdk.start(),this.tracer=o.getTracer("mcp-logger",y.SDK_VERSION),this.initialized=!0,e("Telemetry initialized successfully");const i=async()=>{e("Shutting down telemetry..."),await this.shutdown()};return process.once("SIGTERM",i),process.once("SIGINT",i),this.tracer}getTracer(){return this.tracer}isInitialized(){return this.initialized}setCLIServerInfo(e,s,t){this.cliServerInfo={command:e,args:s,env:t}}getCLIServerInfo(){return this.cliServerInfo}async shutdown(){if(this.sdk)try{await this.sdk.shutdown(),this.sdk=null,this.tracer=null,this.initialized=!1,this.cliServerInfo=null}catch(e){console.error("[mcp-logger] Error shutting down telemetry:",e)}}},E=new class{sessionMap=new Map;sessionCounter=0;conversationMap=new Map;conversationCounter=0;resourceAccessCount=new Map;getOrCreateSessionId(e){if(!this.sessionMap.has(e)){const s=h();this.sessionMap.set(e,s),this.sessionCounter++}return this.sessionMap.get(e)}getOrCreateConversationId(e,s){const t=`${e}-${s}`;return this.conversationMap.has(t)||this.conversationMap.set(t,"conv-"+ ++this.conversationCounter),this.conversationMap.get(t)}trackResourceAccess(e){const s=(this.resourceAccessCount.get(e)||0)+1;return this.resourceAccessCount.set(e,s),s}getResourceAccessCount(e){return this.resourceAccessCount.get(e)||0}clear(){this.sessionMap.clear(),this.conversationMap.clear(),this.resourceAccessCount.clear(),this.sessionCounter=0,this.conversationCounter=0}},S=Symbol("mcp-logger.customEvents"),w=Object.assign(function(s,t){if(!t.apiKey)throw Error("[mcp-logger] apiKey is required");if(!s)throw Error("[mcp-logger] server instance is required");!function(e){I.initialize(e)}(t),function(s){const t=s.setRequestHandler.bind(s);s.setRequestHandler=function(s,o){const i=s.shape?.method,a=i?._def?.value||"unknown";return e("Instrumenting handler: "+a),t(s,async(s,t)=>{const i=Date.now(),u=`${a}-${i}-${Math.random().toString(36).slice(2,8)}`,m=[],p=c.active().setValue(S,m);try{const d=await c.with(p,async()=>await o(s,t)),l=Date.now(),v=r(a,s.params,d,0,void 0);return n({method:a,source:"sdk",transport:"stdio",request:{id:u,timestamp:i,params:s.params},response:{timestamp:l,result:d},duration:l-i,customEvents:m.length>0?m:void 0,contextMetadata:v}),e(`Request completed (${l-i}ms):`,{method:a,customEvents:m.length}),d}catch(t){const o=Date.now(),c=r(a,s.params,void 0,0,void 0);throw n({method:a,source:"sdk",transport:"stdio",request:{id:u,timestamp:i,params:s.params},response:{timestamp:o,error:t},duration:o-i,customEvents:m.length>0?m:void 0,contextMetadata:c}),e("Request failed:",t),t}})},e("Server instrumentation complete")}(s)},{addLog(e){const s=c.active().getValue(S);if(!s)return;const t={level:e.level||"info",message:e.message,metadata:e.metadata,timestamp:e.timestamp||Date.now()};s.push(t);const r=o.getSpan(c.active());r&&r.addEvent("custom."+t.level,{message:t.message,metadata:JSON.stringify(t.metadata||{}),timestamp:t.timestamp})},async shutdown(){await async function(){await I.shutdown()}()}});export{w as trace};
|
package/package.json
CHANGED
package/dist/cli/interceptor.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{Transform as e}from"stream";class s extends e{buffer="";direction;logger;sessionContextStore;debug;constructor(e,s,t,r=!1){super(),this.direction=e,this.logger=s,this.sessionContextStore=t,this.debug=r}_transform(e,s,t){try{if("request"===this.direction)return this.push(e),this.buffer+=e.toString(),this.tryParseMessages(),void t();this.buffer+=e.toString(),this.buffer.length>1e6&&(this.debug&&console.error("[mcp-logger CLI] Buffer size exceeded, clearing..."),this.buffer=""),this.tryParseAndForwardMessages(),t()}catch(e){t(e)}}tryParseMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const s of e){const e=s.trim();if(e)try{const s=JSON.parse(e);this.handleMessage(s)}catch(s){this.debug&&console.error("[mcp-logger CLI] Failed to parse:",e.slice(0,100))}}}tryParseAndForwardMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const s of e){const e=s.trim();if(e)try{const s=JSON.parse(e);"2.0"===s.jsonrpc?(this.push(e+"\n"),this.handleMessage(s)):this.debug&&console.error("[mcp-logger CLI] Non-JSON-RPC JSON ignored:",e.slice(0,100))}catch(s){this.debug&&console.error("[mcp-logger CLI] Non-JSON output filtered:",e.slice(0,100))}}}handleMessage(e){if("request"===this.direction&&"initialize"===e.method&&e.params?.clientInfo){const s=e.params;this.sessionContextStore.setClientInfo({name:s.clientInfo?.name,version:s.clientInfo?.version})}"request"===this.direction&&e.method?this.logger.onRequest(e):"response"===this.direction&&(void 0===e.id||e.method?e.method&&!e.id&&this.logger.onNotification(e):this.logger.onResponse(e))}_flush(e){try{if(this.buffer.trim())try{const e=JSON.parse(this.buffer);this.handleMessage(e)}catch(e){this.debug&&console.error("[mcp-logger CLI] Failed to parse final buffer")}if(this.debug){const e=this.logger.getStats();console.error("[mcp-logger CLI] Stream closed. Pending requests: "+e.pending)}e()}catch(s){e(s)}}}export{s as MessageInterceptor};
|
package/dist/cli/main.js
DELETED
|
@@ -1,2 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
function e(e){return!M.includes(e)}function s(){return O}function t(){return L}function r(e){P=e}function o(){return P||"unknown"}async function n(){if(R)try{await R.shutdown(),R=null,O=null,x=!1,L=null,P=null}catch(e){console.error("[MCP Logger] Error shutting down telemetry:",e)}}function i(e,s){for(const[t,r]of Object.entries(s))null!=r&&e.setAttribute(t,r)}function c(e,s=2e5){try{const t=JSON.stringify(e);return t.length>s?t.slice(0,s)+"... (truncated)":t}catch(e){return null}}function a(e,s){return e.startsWith("resources/")?{type:e.split("/")[1],uri:s?.uri||s?.path||s?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:s?.name||s?.promptId}:"tools/call"===e?{type:"tool",uri:s?.name}:s?.resourceType&&s?.resourceUri?{type:s.resourceType,uri:s.resourceUri}:{type:void 0,uri:void 0}}function p(e,s,t,r,o){const n=function(e,s){const t=e?.getClientInfo();if(t?.name||t?.version)return{name:t.name,version:t.version};const r=e?.getHeaders()||s;if(r){const e=r["user-agent"]||r["User-Agent"];if(e){const s=e.match(/^([^\/]+)\/([^\s]+)/);if(s)return{name:s[1],version:s[2]}}}return{name:void 0,version:void 0}}(r,o),i=function(e){if(!T.has(e)){const s=w();T.set(e,s)}return T.get(e)}(`${n.name||"unknown"}-${n.version||"0"}`),c=function(e,s){const t=`${e}-${s}`;return k.has(t)||k.set(t,"conv-"+ ++$),k.get(t)}(i,e),p=function(e,s){return e?.userId||e?.user_id?e.userId||e.user_id:s?s["x-user-id"]||s["X-User-Id"]:void 0}(s,o),m=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(s),u=a(e,s);u.uri&&function(e){const s=(_.get(e)||0)+1;_.set(e,s)}(u.uri);const d=function(e,s){return void 0!==e?.cost?e.cost:void 0!==s?.cost?s.cost:void 0}(s,t),l={};return i&&(l.sessionId=i),c&&(l.conversationId=c),p&&(l.userId=p),n.name&&(l.clientName=n.name),n.version&&(l.clientVersion=n.version),m&&(l.permissionLevel=m),void 0!==d&&(l.cost=d),l}function m(e,s){const t=a(e,s);if(!t.uri)return{};const r=_.get(t.uri)||0;return{resourceType:t.type,resourceUri:t.uri,resourceAccessCount:r}}import{spawn as u,execSync as d}from"child_process";import{program as l}from"commander";import{NodeSDK as g}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as h}from"@opentelemetry/exporter-trace-otlp-http";import{Resource as f}from"@opentelemetry/resources";import{trace as v,SpanStatusCode as I}from"@opentelemetry/api";import{readFileSync as y}from"fs";import{fileURLToPath as S}from"url";import{dirname as q,join as C}from"path";import{Transform as N}from"stream";import{ulid as w}from"ulid";const E={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const e=S(import.meta.url),s=q(e),t=C(s,"..","..","package.json");return JSON.parse(y(t,"utf-8")).version||"1.0.0"}catch(e){return console.error("[MCP Logger] Failed to read package version:",e),"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"},M=["notifications/initialized"];let R=null,O=null,x=!1,L=null,P=null;class b extends N{buffer="";direction;logger;sessionContextStore;debug;constructor(e,s,t,r=!1){super(),this.direction=e,this.logger=s,this.sessionContextStore=t,this.debug=r}_transform(e,s,t){try{if("request"===this.direction)return this.push(e),this.buffer+=e.toString(),this.tryParseMessages(),void t();this.buffer+=e.toString(),this.buffer.length>1e6&&(this.debug&&console.error("[mcp-logger CLI] Buffer size exceeded, clearing..."),this.buffer=""),this.tryParseAndForwardMessages(),t()}catch(e){t(e)}}tryParseMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const s of e){const e=s.trim();if(e)try{const s=JSON.parse(e);this.handleMessage(s)}catch(s){this.debug&&console.error("[mcp-logger CLI] Failed to parse:",e.slice(0,100))}}}tryParseAndForwardMessages(){const e=this.buffer.split("\n");this.buffer=e.pop()||"";for(const s of e){const e=s.trim();if(e)try{const s=JSON.parse(e);"2.0"===s.jsonrpc?(this.push(e+"\n"),this.handleMessage(s)):this.debug&&console.error("[mcp-logger CLI] Non-JSON-RPC JSON ignored:",e.slice(0,100))}catch(s){this.debug&&console.error("[mcp-logger CLI] Non-JSON output filtered:",e.slice(0,100))}}}handleMessage(e){if("request"===this.direction&&"initialize"===e.method&&e.params?.clientInfo){const s=e.params;this.sessionContextStore.setClientInfo({name:s.clientInfo?.name,version:s.clientInfo?.version})}"request"===this.direction&&e.method?this.logger.onRequest(e):"response"===this.direction&&(void 0===e.id||e.method?e.method&&!e.id&&this.logger.onNotification(e):this.logger.onResponse(e))}_flush(e){try{if(this.buffer.trim())try{const e=JSON.parse(this.buffer);this.handleMessage(e)}catch(e){this.debug&&console.error("[mcp-logger CLI] Failed to parse final buffer")}if(this.debug){const e=this.logger.getStats();console.error("[mcp-logger CLI] Stream closed. Pending requests: "+e.pending)}e()}catch(s){e(s)}}}const T=new Map,k=new Map;let $=0;const _=new Map;class A{pendingRequests=new Map;debug;TIMEOUT=3e4;sessionContextStore;constructor(e,s=!1){this.debug=s,this.sessionContextStore=e}onRequest(s){e(s.method)&&(s.id?(this.pendingRequests.set(s.id,{request:s,timestamp:Date.now()}),"initialize"===s.method&&s.params?.clientInfo&&this.sessionContextStore.setClientInfo({name:s.params.clientInfo.name,version:s.params.clientInfo.version}),setTimeout(()=>this.cleanupStale(s.id),this.TIMEOUT)):this.createRequestOnlySpan(s,Date.now()))}onResponse(e){if(!e.id)return;const s=this.pendingRequests.get(e.id);if("initialize"===s?.request.method)if(e.result?.serverInfo?.version)r(e.result.serverInfo.version);else{const s=e.result?.capabilities?.implementation?.version;s&&r(s)}if(!s)return void this.createResponseOnlySpan(e,Date.now());const t=Date.now(),o=t-s.timestamp;this.createPairedSpan(s.request,e,s.timestamp,t,o),this.pendingRequests.delete(e.id)}onNotification(s){e(s.method)&&this.createResponseOnlySpan({jsonrpc:"2.0",id:`notification-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,method:s.method},Date.now())}createPairedSpan(e,r,n,a,u){const d=p(e.method,e.params,r.result,this.sessionContextStore,void 0);!function(e){const r=s();if(!r)return void console.error("[MCP Logger] Tracer not initialized, cannot create span");const n="mcp."+e.method;r.startActiveSpan(n,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.request.id":e.request.id+"","mcp.request.method":e.method,"mcp.request.timestamp":e.request.timestamp,"mcp.request.params":c(e.request.params)||"{}","mcp.request.params.size":JSON.stringify(e.request.params||{}).length,"mcp.response.id":e.request.id+"","mcp.response.timestamp":e.response.timestamp,"mcp.duration_ms":e.duration};if("tools/call"===e.method&&e.request.params){const s=e.request.params.name,t=e.request.params.arguments;if(s&&(r["mcp.tool.name"]=s),t){const e=c(t);e&&(r["mcp.tool.arguments"]=e,r["mcp.tool.arguments.size"]=JSON.stringify(t).length)}}if(void 0!==e.response.result){const s=c(e.response.result);s&&(r["mcp.response.result"]=s,r["mcp.response.result.size"]=JSON.stringify(e.response.result).length)}if(e.request.headers){const s=c(e.request.headers);s&&(r["mcp.headers"]=s,r["mcp.headers.size"]=JSON.stringify(e.request.headers).length)}if("cli"===e.source){const e=t();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}));const s=o();r["mcp.server.version"]=s}const n=e.contextMetadata||p(e.method,e.request.params,e.response.result,void 0,e.request.headers);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost);const a=m(e.method,e.request.params);if(a.resourceType&&(r["mcp.resource.type"]=a.resourceType),a.resourceUri&&(r["mcp.resource.uri"]=a.resourceUri),a.resourceAccessCount&&(r["mcp.resource.access_count"]=a.resourceAccessCount),e.customEvents&&e.customEvents.length>0&&(r["mcp.events"]=JSON.stringify(e.customEvents),r["mcp.events.count"]=e.customEvents.length,e.customEvents.forEach(e=>{s.addEvent("custom."+(e.level||"info"),{message:e.message,metadata:JSON.stringify(e.metadata||{}),timestamp:e.timestamp||Date.now()})})),e.response.error){let t;r["mcp.error"]=!0,t=e.response.error instanceof Error?e.response.error.message:"string"==typeof e.response.error?e.response.error:c(e.response.error)||"Unknown error",r["mcp.error.message"]=t,e.response.error instanceof Error&&s.recordException(e.response.error),s.setStatus({code:I.ERROR,message:t})}else s.setStatus({code:I.OK});i(s,r)}catch(e){console.error("[MCP Logger] Error creating paired span:",e),s.setStatus({code:I.ERROR,message:e+""})}finally{s.end()}})}({method:e.method,source:"cli",transport:"stdio",request:{id:e.id,timestamp:n,params:e.params},response:{timestamp:a,result:r.result,error:r.error},duration:u,contextMetadata:d})}cleanupStale(e){const s=this.pendingRequests.get(e);s&&Date.now()-s.timestamp>this.TIMEOUT&&(this.createRequestOnlySpan(s.request,s.timestamp),this.pendingRequests.delete(e))}createRequestOnlySpan(e,r){const n=p(e.method,e.params,void 0,this.sessionContextStore,void 0);!function(e){const r=s();if(!r)return void console.error("[MCP Logger] Tracer not initialized, cannot create span");const n="mcp."+e.method;r.startActiveSpan(n,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.request.id":e.request.id+"","mcp.request.method":e.method,"mcp.request.timestamp":e.request.timestamp,"mcp.request.params":c(e.request.params)||"{}","mcp.request.params.size":JSON.stringify(e.request.params||{}).length};if("tools/call"===e.method&&e.request.params){const s=e.request.params.name,t=e.request.params.arguments;if(s&&(r["mcp.tool.name"]=s),t){const e=c(t);e&&(r["mcp.tool.arguments"]=e,r["mcp.tool.arguments.size"]=JSON.stringify(t).length)}}if("cli"===e.source){const e=t();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}));const s=o();r["mcp.server.version"]=s}const n=e.contextMetadata||p(e.method,e.request.params,void 0,void 0,e.request.headers);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost);const a=m(e.method,e.request.params);a.resourceType&&(r["mcp.resource.type"]=a.resourceType),a.resourceUri&&(r["mcp.resource.uri"]=a.resourceUri),a.resourceAccessCount&&(r["mcp.resource.access_count"]=a.resourceAccessCount),s.setStatus({code:I.OK}),i(s,r)}catch(e){console.error("[MCP Logger] Error creating request-only span:",e),s.setStatus({code:I.ERROR,message:e+""})}finally{s.end()}})}({method:e.method,source:"cli",transport:"stdio",request:{id:e.id,timestamp:r,params:e.params},contextMetadata:n})}createResponseOnlySpan(e,r){const n=p(e.method||"unknown",void 0,e.result,this.sessionContextStore,void 0);!function(e){const r=s();if(!r)return void console.error("[MCP Logger] Tracer not initialized, cannot create span");const n="mcp."+e.method;r.startActiveSpan(n,s=>{try{const r={"mcp.source":e.source,"mcp.transport":e.transport,"mcp.response.id":e.response.id+"","mcp.response.method":e.method,"mcp.response.timestamp":e.response.timestamp};if(void 0!==e.response.result){const s=c(e.response.result);s&&(r["mcp.response.result"]=s,r["mcp.response.result.size"]=JSON.stringify(e.response.result).length)}if(e.response.error){let t;r["mcp.error"]=!0,t=e.response.error instanceof Error?e.response.error.message:"string"==typeof e.response.error?e.response.error:c(e.response.error)||"Unknown error",r["mcp.error.message"]=t,e.response.error instanceof Error&&s.recordException(e.response.error),s.setStatus({code:I.ERROR,message:t})}else s.setStatus({code:I.OK});if("cli"===e.source){const e=t();e&&(r["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}));const s=o();r["mcp.server.version"]=s}const n=e.contextMetadata||p(e.method,void 0,e.response.result,void 0,void 0);n.sessionId&&(r["mcp.session.id"]=n.sessionId),n.conversationId&&(r["mcp.conversation.id"]=n.conversationId),n.sessionId&&n.conversationId&&(r["mcp.trace.id"]=`${n.sessionId}:${n.conversationId}`),n.userId&&(r["mcp.user.id"]=n.userId),n.clientName&&(r["mcp.client.name"]=n.clientName),n.clientVersion&&(r["mcp.client.version"]=n.clientVersion),n.permissionLevel&&(r["mcp.permission.level"]=n.permissionLevel),void 0!==n.cost&&(r["mcp.cost"]=n.cost),i(s,r)}catch(e){console.error("[MCP Logger] Error creating response-only span:",e),s.setStatus({code:I.ERROR,message:e+""})}finally{s.end()}})}({method:e.method||"same_request_method",source:"cli",transport:"stdio",response:{id:e.id,timestamp:r,result:e.result,error:e.error},contextMetadata:n})}getStats(){return{pending:this.pendingRequests.size}}clear(){this.pendingRequests.clear()}}class J{context={};getClientInfo(){return this.context.clientInfo}setClientInfo(e){this.context.clientInfo=e}getHeaders(){return this.context.headers}setHeaders(e){this.context.headers=e}snapshot(){return{clientInfo:this.context.clientInfo?{...this.context.clientInfo}:void 0,headers:this.context.headers?{...this.context.headers}:void 0}}}const z=new Set(["npx","node","uvx","python","python3","pip","pipx","deno","bun"]);l.name("mcp-logger").description("Add observability to any MCP server without code changes").version("1.0.0").requiredOption("-k, --api-key <key>","Aware API key").option("-e, --endpoint <url>","Custom OTLP endpoint").argument("<command...>","MCP server command to wrap").action(async(e,s)=>{try{const t=!1,o=function(e){const s={};for(const t of e){const e=process.env[t];void 0!==e&&(s[t]=e)}return s}(function(){try{return d("aware mcpenv sync",{encoding:"utf-8",timeout:1e4,stdio:["pipe","pipe","pipe"]}),d("aware mcpenv keys",{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]}).trim().split("\n").filter(e=>e.length>0)}catch(e){return console.error("[MCP Logger CLI] aware CLI not found or mcpenv sync/keys failed, skipping env extraction"),[]}}()),[i,...c]=e,a=function(e){for(const s of e){if(z.has(s))continue;const e=s.match(/^(@[^@]+\/[^@]+)@(.+)$/);if(e)return{packageName:e[1],version:e[2]};const t=s.match(/^([^@]+)@(.+)$/);if(t)return{packageName:t[1],version:t[2]};const r=s.match(/^(@[^@]+\/[^@]+)$/);if(r)return{packageName:r[1],version:"latest"};if(s.match(/^[a-z0-9-]+$/)&&!s.includes("/"))return{packageName:s,version:"latest"}}return null}(c.filter(e=>!e.startsWith("-")));let p,m;if(p=a?.packageName?a.packageName:i.split("/").pop()||i||E.SERVICE_NAME_PREFIX+"-unknown",a&&(m=a.version,"latest"===a.version)){const e="uvx"===i?"pip":"npm",s=function(e,s){try{let t;t="pip"===s?"pip index versions "+e:`npm view ${e} version --json`;const r=d(t,{encoding:"utf-8",timeout:5e3,stdio:["pipe","pipe","pipe"]});if("pip"===s){const e=r.match(/Available versions:\s*([^\n]+)/);return e?e[1].split(",").map(e=>e.trim())[0]:null}{const e=r.trim().replace(/^["']|["']$/g,""),s=e.match(/^(\d+\.\d+\.\d+(?:-[\w.]+)?)/);return s?s[1]:e}}catch(e){return null}}(a.packageName,e);s&&(m=s)}!function(e){if(x)return O;const s=e.endpoint||E.ENDPOINT,t=e.serviceName||`${E.SERVICE_NAME_PREFIX}-${Math.random().toString(36).slice(2,8)}`;R=new g({resource:new f({"service.name":t,"service.version":E.SDK_VERSION}),traceExporter:new h({url:s,headers:{"x-api-key":e.apiKey}})}),R.start(),O=v.getTracer("mcp-logger",E.SDK_VERSION),x=!0;const r=async()=>{await n()};process.once("SIGTERM",r),process.once("SIGINT",r)}({...s,serviceName:p,debug:t}),console.error("[MCP Logger CLI] Starting MCP server:",e.join(" ")),m&&r(m),function(e,s,t){L={command:e,args:s,env:t}}(i,c,o);const l=u(i,c,{stdio:["pipe","pipe","inherit"],env:{...process.env,MCP_LOGGER_ENABLED:"true"}}),I=new J,y=new A(I,t),S=new b("request",y,I,t);process.stdin.pipe(S).pipe(l.stdin);const q=new b("response",y,I,t);l.stdout.pipe(q).pipe(process.stdout),l.on("error",async e=>{console.error("[MCP Logger CLI] Failed to start MCP server:",e),y.clear(),await n(),process.exit(1)}),l.on("exit",async(e,s)=>{console.error(`[MCP Logger CLI] MCP server exited with code ${e}, signal ${s}`),y.clear(),await n(),process.exit(e||0)});let C=!1;const N=async e=>{C||(C=!0,console.error(`[MCP Logger CLI] Received ${e}, shutting down...`),l.kill(e),await Promise.race([new Promise(e=>l.once("exit",e)),new Promise(e=>setTimeout(e,5e3))]),await n(),process.exit(0))};process.on("SIGTERM",()=>N("SIGTERM")),process.on("SIGINT",()=>N("SIGINT"))}catch(e){console.error("[MCP Logger CLI] Fatal error:",e),await n(),process.exit(1)}}),l.parse();
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(e){return!a.includes(e)}function t(e,t,n,o,s){const r=function(e,t){const n=e?.getClientInfo();if(n?.name||n?.version)return{name:n.name,version:n.version};const o=e?.getHeaders()||t;if(o){const e=o["user-agent"]||o["User-Agent"];if(e){const t=e.match(/^([^\/]+)\/([^\s]+)/);if(t)return{name:t[1],version:t[2]}}}return{name:void 0,version:void 0}}(o,s),a=function(e){if(!c.has(e)){const t=i();c.set(e,t)}return c.get(e)}(`${r.name||"unknown"}-${r.version||"0"}`),m=function(e,t){const n=`${e}-${t}`;return p.has(n)||p.set(n,"conv-"+ ++u),p.get(n)}(a,e),l=function(e){if(e?.userId||e?.user_id)return e.userId||e.user_id}(t),h=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(t),f=function(e,t){return e.startsWith("resources/")?{type:e.split("/")[1],uri:t?.uri||t?.path||t?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:t?.name||t?.promptId}:"tools/call"===e?{type:"tool",uri:t?.name}:t?.resourceType&&t?.resourceUri?{type:t.resourceType,uri:t.resourceUri}:{type:void 0,uri:void 0}}(e,t);f.uri&&function(e){const t=(d.get(e)||0)+1;d.set(e,t)}(f.uri);const v=function(e,t){return void 0!==e?.cost?e.cost:void 0!==t?.cost?t.cost:void 0}(t,n),g={};return a&&(g.sessionId=a),m&&(g.conversationId=m),l&&(g.userId=l),r.name&&(g.clientName=r.name),r.version&&(g.clientVersion=r.version),h&&(g.permissionLevel=h),void 0!==v&&(g.cost=v),g}import{readFileSync as n}from"fs";import{fileURLToPath as o}from"url";import{dirname as s,join as r}from"path";import"@opentelemetry/api";import"@opentelemetry/sdk-node";import"@opentelemetry/exporter-trace-otlp-http";import"@opentelemetry/resources";import{ulid as i}from"ulid";!function(){try{const e=o(import.meta.url),t=s(e),i=r(t,"..","..","package.json");return JSON.parse(n(i,"utf-8")).version||"1.0.0"}catch(e){return console.error("[MCP Logger] Failed to read package version:",e),"1.0.0"}}();const a=["notifications/initialized"],c=new Map,p=new Map;let u=0;const d=new Map;class m{pendingRequests=new Map;debug;TIMEOUT=3e4;sessionContextStore;constructor(e,t=!1){this.debug=t,this.sessionContextStore=e}onRequest(t){e(t.method)&&(t.id?(this.pendingRequests.set(t.id,{request:t,timestamp:Date.now()}),"initialize"===t.method&&t.params?.clientInfo&&this.sessionContextStore.setClientInfo({name:t.params.clientInfo.name,version:t.params.clientInfo.version}),setTimeout(()=>this.cleanupStale(t.id),this.TIMEOUT)):this.createRequestOnlySpan(t,Date.now()))}onResponse(e){if(!e.id)return;const t=this.pendingRequests.get(e.id);if("initialize"===t?.request.method&&(e.result?.serverInfo?.version?e.result.serverInfo.version:e.result),!t)return void this.createResponseOnlySpan(e,Date.now());const n=Date.now(),o=n-t.timestamp;this.createPairedSpan(t.request,e,t.timestamp,n,o),this.pendingRequests.delete(e.id)}onNotification(t){e(t.method)&&this.createResponseOnlySpan({jsonrpc:"2.0",id:`notification-${Date.now()}-${Math.random().toString(36).slice(2,8)}`,method:t.method},Date.now())}createPairedSpan(e,n,o,s,r){t(e.method,e.params,n.result,this.sessionContextStore,void 0),e.method,e.id,e.params,n.result,n.error,console.error("[MCP Logger] Tracer not initialized, cannot create span")}cleanupStale(e){const t=this.pendingRequests.get(e);t&&Date.now()-t.timestamp>this.TIMEOUT&&(this.createRequestOnlySpan(t.request,t.timestamp),this.pendingRequests.delete(e))}createRequestOnlySpan(e,n){t(e.method,e.params,void 0,this.sessionContextStore,void 0),e.method,e.id,e.params,console.error("[MCP Logger] Tracer not initialized, cannot create span")}createResponseOnlySpan(e,n){t(e.method||"unknown",void 0,e.result,this.sessionContextStore,void 0),e.method,e.id,e.result,e.error,console.error("[MCP Logger] Tracer not initialized, cannot create span")}getStats(){return{pending:this.pendingRequests.size}}clear(){this.pendingRequests.clear()}}export{m as MCPMessageLogger};
|
package/dist/core/config.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function r(r){return!a.includes(r)}import{readFileSync as o}from"fs";import{fileURLToPath as t}from"url";import{dirname as e,join as i}from"path";const n={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const r=t(import.meta.url),n=e(r),a=i(n,"..","..","package.json");return JSON.parse(o(a,"utf-8")).version||"1.0.0"}catch(r){return console.error("[MCP Logger] Failed to read package version:",r),"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"},a=["notifications/initialized"];export{n as CONFIG,r as shouldTrackMethod};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function r(r){console.error("[MCP Logger] Tracer not initialized, cannot create span")}function e(r){console.error("[MCP Logger] Tracer not initialized, cannot create span")}function o(r){console.error("[MCP Logger] Tracer not initialized, cannot create span")}import"@opentelemetry/api";import"@opentelemetry/sdk-node";import"@opentelemetry/exporter-trace-otlp-http";import"@opentelemetry/resources";import{readFileSync as t}from"fs";import{fileURLToPath as n}from"url";import{dirname as i,join as a}from"path";import"ulid";!function(){try{const r=n(import.meta.url),e=i(r),o=a(e,"..","..","package.json");return JSON.parse(t(o,"utf-8")).version||"1.0.0"}catch(r){return console.error("[MCP Logger] Failed to read package version:",r),"1.0.0"}}();export{r as createPairedSpan,e as createRequestOnlySpan,o as createResponseOnlySpan};
|
package/dist/core/span-utils.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function t(t,r){for(const[e,n]of Object.entries(r))null!=n&&t.setAttribute(e,n)}function r(t,r,e,n){try{e?t.addEvent(r,e):t.addEvent(r)}catch(t){n&&console.error("[MCP Logger] Failed to add span event:",t)}}function e(t,r,e){const n=r instanceof Error?r.message:"Unknown error",o=r instanceof Error?r.constructor.name:"Error";r instanceof Error&&t.recordException(r),t.setStatus({code:s.ERROR,message:n}),t.setAttribute("error",!0),t.setAttribute("error.type",o),t.setAttribute("error.message",n),e&&console.error("[MCP Logger] Error recorded in span:",r)}function n(t){t.setStatus({code:s.OK})}function o(t,r=2e5){try{const e=JSON.stringify(t);return e.length>r?e.slice(0,r)+"... (truncated)":e}catch(t){return null}}function c(){const t={},r=a.active(),e=i.getSpan(r);if(e){const r=e.spanContext();r&&(t.traceparent=`00-${r.traceId}-${r.spanId}-01`)}return t}import{SpanStatusCode as s,context as a,trace as i}from"@opentelemetry/api";export{r as addSpanEvent,c as getTraceHeaders,n as markSpanSuccess,e as recordSpanError,o as safeStringify,t as setSpanAttributes};
|
package/dist/core/telemetry.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(e){if(I)return e.debug&&console.error("[MCP Logger] Telemetry already initialized, returning existing tracer"),S;const r=e.endpoint||y.ENDPOINT,o=e.serviceName||`${y.SERVICE_NAME_PREFIX}-${Math.random().toString(36).slice(2,8)}`;e.debug&&(console.error("[MCP Logger] Initializing telemetry..."),console.error("[MCP Logger] Endpoint: "+r),console.error("[MCP Logger] Service: "+o)),E=new s({resource:new a({"service.name":o,"service.version":y.SDK_VERSION}),traceExporter:new u({url:r,headers:{"x-api-key":e.apiKey}})}),E.start(),S=p.getTracer("mcp-logger",y.SDK_VERSION),I=!0,e.debug&&console.error("[MCP Logger] Telemetry initialized successfully");const n=async()=>{e.debug&&console.error("[MCP Logger] Shutting down telemetry..."),await l()};return process.once("SIGTERM",n),process.once("SIGINT",n),S}function r(){return S}function o(){return I}function n(e,r,o){M={command:e,args:r,env:o}}function t(){return M}function i(e){N=e}function c(){return N||"unknown"}async function l(){if(E)try{await E.shutdown(),E=null,S=null,I=!1,M=null,N=null}catch(e){console.error("[MCP Logger] Error shutting down telemetry:",e)}}import{NodeSDK as s}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as u}from"@opentelemetry/exporter-trace-otlp-http";import{Resource as a}from"@opentelemetry/resources";import{trace as p}from"@opentelemetry/api";import{readFileSync as g}from"fs";import{fileURLToPath as m}from"url";import{dirname as f,join as d}from"path";const y={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const e=m(import.meta.url),r=f(e),o=d(r,"..","..","package.json");return JSON.parse(g(o,"utf-8")).version||"1.0.0"}catch(e){return console.error("[MCP Logger] Failed to read package version:",e),"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"};let E=null,S=null,I=!1,M=null,N=null;export{t as getCLIServerInfo,c as getMCPServerVersion,r as getTracer,e as initializeTelemetry,o as isInitializedTelemetry,n as setCLIServerInfo,i as setMCPServerVersion,l as shutdownTelemetry};
|
package/dist/core/types.d.ts
DELETED
|
@@ -1,228 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* κ³΅ν΅ νμ
μ μ
|
|
3
|
-
*/
|
|
4
|
-
/**
|
|
5
|
-
* ν
λ λ©νΈλ¦¬ μ΄κΈ°ν μ΅μ
|
|
6
|
-
*/
|
|
7
|
-
interface TelemetryOptions {
|
|
8
|
-
/**
|
|
9
|
-
* API Key for authentication (νμ)
|
|
10
|
-
*/
|
|
11
|
-
apiKey: string;
|
|
12
|
-
/**
|
|
13
|
-
* μλΉμ€ μ΄λ¦ (μ΅μ
)
|
|
14
|
-
* μ§μ νμ§ μμΌλ©΄ μλμΌλ‘ 'mcp-server-{random}' νμμΌλ‘ μμ±
|
|
15
|
-
*/
|
|
16
|
-
serviceName?: string;
|
|
17
|
-
/**
|
|
18
|
-
* 컀μ€ν
OTLP μλν¬μΈνΈ (μ΅μ
)
|
|
19
|
-
* κΈ°λ³Έκ°: CONFIG.ENDPOINT
|
|
20
|
-
*/
|
|
21
|
-
endpoint?: string;
|
|
22
|
-
/**
|
|
23
|
-
* λλ²κ·Έ λ‘κ·Έ νμ±ν (μ΅μ
)
|
|
24
|
-
*/
|
|
25
|
-
debug?: boolean;
|
|
26
|
-
}
|
|
27
|
-
/**
|
|
28
|
-
* Span μμ± μΈν°νμ΄μ€
|
|
29
|
-
*/
|
|
30
|
-
interface SpanAttributes {
|
|
31
|
-
[key: string]: string | number | boolean | undefined;
|
|
32
|
-
}
|
|
33
|
-
/**
|
|
34
|
-
* MCP λ©μμ§ λ°©ν₯
|
|
35
|
-
*/
|
|
36
|
-
type MessageDirection = 'request' | 'response';
|
|
37
|
-
/**
|
|
38
|
-
* JSON-RPC λ©μμ§ νμ
|
|
39
|
-
*/
|
|
40
|
-
interface JSONRPCMessage {
|
|
41
|
-
jsonrpc: '2.0';
|
|
42
|
-
id?: string | number;
|
|
43
|
-
method?: string;
|
|
44
|
-
params?: any;
|
|
45
|
-
result?: any;
|
|
46
|
-
error?: {
|
|
47
|
-
code: number;
|
|
48
|
-
message: string;
|
|
49
|
-
data?: any;
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
/**
|
|
53
|
-
* JSON-RPC Request νμ
|
|
54
|
-
*/
|
|
55
|
-
interface JSONRPCRequest extends JSONRPCMessage {
|
|
56
|
-
method: string;
|
|
57
|
-
params?: any;
|
|
58
|
-
}
|
|
59
|
-
/**
|
|
60
|
-
* JSON-RPC Response νμ
|
|
61
|
-
*/
|
|
62
|
-
interface JSONRPCResponse extends JSONRPCMessage {
|
|
63
|
-
id: string | number;
|
|
64
|
-
result?: any;
|
|
65
|
-
error?: {
|
|
66
|
-
code: number;
|
|
67
|
-
message: string;
|
|
68
|
-
data?: any;
|
|
69
|
-
};
|
|
70
|
-
}
|
|
71
|
-
/**
|
|
72
|
-
* MCP Span λ°μ΄ν° ꡬ쑰 (ES μ΅μ ν)
|
|
73
|
-
* Request/Response νλκ° optionalμ΄λ―λ‘ log_type λΆνμ
|
|
74
|
-
* - requestλ§ μμ = request-only
|
|
75
|
-
* - responseλ§ μμ = response-only
|
|
76
|
-
* - λ λ€ μμ = paired (duration ν¬ν¨)
|
|
77
|
-
*/
|
|
78
|
-
interface MCPSpanData {
|
|
79
|
-
'mcp.source': 'cli' | 'sdk';
|
|
80
|
-
'mcp.transport': 'stdio' | 'sse';
|
|
81
|
-
'mcp.request.id'?: string;
|
|
82
|
-
'mcp.request.method'?: string;
|
|
83
|
-
'mcp.request.timestamp'?: number;
|
|
84
|
-
'mcp.request.params'?: string;
|
|
85
|
-
'mcp.request.params.size'?: number;
|
|
86
|
-
'mcp.response.id'?: string;
|
|
87
|
-
'mcp.response.method'?: string;
|
|
88
|
-
'mcp.response.timestamp'?: number;
|
|
89
|
-
'mcp.response.result'?: string;
|
|
90
|
-
'mcp.response.result.size'?: number;
|
|
91
|
-
'mcp.duration_ms'?: number;
|
|
92
|
-
'mcp.tool.name'?: string;
|
|
93
|
-
'mcp.tool.arguments'?: string;
|
|
94
|
-
'mcp.tool.arguments.size'?: number;
|
|
95
|
-
'mcp.headers'?: string;
|
|
96
|
-
'mcp.headers.size'?: number;
|
|
97
|
-
'mcp.events'?: string;
|
|
98
|
-
'mcp.events.count'?: number;
|
|
99
|
-
'mcp.cli'?: string;
|
|
100
|
-
'mcp.server.version'?: string;
|
|
101
|
-
'mcp.error'?: boolean;
|
|
102
|
-
'mcp.error.code'?: number;
|
|
103
|
-
'mcp.error.message'?: string;
|
|
104
|
-
'mcp.session.id'?: string;
|
|
105
|
-
'mcp.conversation.id'?: string;
|
|
106
|
-
'mcp.trace.id'?: string;
|
|
107
|
-
'mcp.user.id'?: string;
|
|
108
|
-
'mcp.client.name'?: string;
|
|
109
|
-
'mcp.client.version'?: string;
|
|
110
|
-
'mcp.permission.level'?: string;
|
|
111
|
-
'mcp.resource.type'?: string;
|
|
112
|
-
'mcp.resource.uri'?: string;
|
|
113
|
-
'mcp.resource.access_count'?: number;
|
|
114
|
-
'mcp.cost'?: number;
|
|
115
|
-
}
|
|
116
|
-
/**
|
|
117
|
-
* 컀μ€ν
λ‘κ·Έ μνΈλ¦¬
|
|
118
|
-
*/
|
|
119
|
-
interface CustomLogEntry {
|
|
120
|
-
/**
|
|
121
|
-
* λ‘κ·Έ λ 벨
|
|
122
|
-
*/
|
|
123
|
-
level?: 'info' | 'warn' | 'error';
|
|
124
|
-
/**
|
|
125
|
-
* λ‘κ·Έ λ©μμ§
|
|
126
|
-
*/
|
|
127
|
-
message: string;
|
|
128
|
-
/**
|
|
129
|
-
* μΆκ° λ©νλ°μ΄ν° (μμ νμ)
|
|
130
|
-
*/
|
|
131
|
-
metadata?: Record<string, any>;
|
|
132
|
-
/**
|
|
133
|
-
* νμμ€ν¬ν (μλ μμ± κ°λ₯)
|
|
134
|
-
*/
|
|
135
|
-
timestamp?: number;
|
|
136
|
-
}
|
|
137
|
-
/**
|
|
138
|
-
* MCP 컨ν
μ€νΈ λ©νλ°μ΄ν°
|
|
139
|
-
*/
|
|
140
|
-
interface MCPContextMetadata {
|
|
141
|
-
sessionId?: string;
|
|
142
|
-
conversationId?: string;
|
|
143
|
-
userId?: string;
|
|
144
|
-
clientName?: string;
|
|
145
|
-
clientVersion?: string;
|
|
146
|
-
permissionLevel?: string;
|
|
147
|
-
cost?: number;
|
|
148
|
-
}
|
|
149
|
-
/**
|
|
150
|
-
* Session-level context shared across a single MCP connection
|
|
151
|
-
*/
|
|
152
|
-
interface SessionContext {
|
|
153
|
-
clientInfo?: {
|
|
154
|
-
name?: string;
|
|
155
|
-
version?: string;
|
|
156
|
-
};
|
|
157
|
-
headers?: Record<string, string>;
|
|
158
|
-
}
|
|
159
|
-
/**
|
|
160
|
-
* Abstraction for reading/writing session-scoped context for a single connection.
|
|
161
|
-
*/
|
|
162
|
-
interface SessionContextStore {
|
|
163
|
-
getClientInfo(): {
|
|
164
|
-
name?: string;
|
|
165
|
-
version?: string;
|
|
166
|
-
} | undefined;
|
|
167
|
-
setClientInfo(info: {
|
|
168
|
-
name?: string;
|
|
169
|
-
version?: string;
|
|
170
|
-
} | undefined): void;
|
|
171
|
-
getHeaders(): Record<string, string> | undefined;
|
|
172
|
-
setHeaders(headers: Record<string, string> | undefined): void;
|
|
173
|
-
snapshot(): SessionContext;
|
|
174
|
-
}
|
|
175
|
-
/**
|
|
176
|
-
* Paired Span μ
λ ₯ λ°μ΄ν°
|
|
177
|
-
*/
|
|
178
|
-
interface PairedSpanInput {
|
|
179
|
-
method: string;
|
|
180
|
-
source: 'cli' | 'sdk';
|
|
181
|
-
transport: 'stdio' | 'sse';
|
|
182
|
-
request: {
|
|
183
|
-
id: string | number;
|
|
184
|
-
timestamp: number;
|
|
185
|
-
params: any;
|
|
186
|
-
headers?: Record<string, string>;
|
|
187
|
-
};
|
|
188
|
-
response: {
|
|
189
|
-
timestamp: number;
|
|
190
|
-
result?: any;
|
|
191
|
-
error?: any;
|
|
192
|
-
};
|
|
193
|
-
duration: number;
|
|
194
|
-
customEvents?: CustomLogEntry[];
|
|
195
|
-
contextMetadata?: MCPContextMetadata;
|
|
196
|
-
}
|
|
197
|
-
/**
|
|
198
|
-
* Response-only Span μ
λ ₯ λ°μ΄ν° (notification λ± responseκ° μλ κ²½μ°)
|
|
199
|
-
*/
|
|
200
|
-
interface ResponseOnlySpanInput {
|
|
201
|
-
method: string;
|
|
202
|
-
source: 'cli' | 'sdk';
|
|
203
|
-
transport: 'stdio' | 'sse';
|
|
204
|
-
response: {
|
|
205
|
-
id: string | number;
|
|
206
|
-
timestamp: number;
|
|
207
|
-
result?: any;
|
|
208
|
-
error?: any;
|
|
209
|
-
};
|
|
210
|
-
contextMetadata?: MCPContextMetadata;
|
|
211
|
-
}
|
|
212
|
-
/**
|
|
213
|
-
* Request-only Span μ
λ ₯ λ°μ΄ν° (timeout λ±μΌλ‘ responseκ° μλ κ²½μ°)
|
|
214
|
-
*/
|
|
215
|
-
interface RequestOnlySpanInput {
|
|
216
|
-
method: string;
|
|
217
|
-
source: 'cli' | 'sdk';
|
|
218
|
-
transport: 'stdio' | 'sse';
|
|
219
|
-
request: {
|
|
220
|
-
id: string | number;
|
|
221
|
-
timestamp: number;
|
|
222
|
-
params: any;
|
|
223
|
-
headers?: Record<string, string>;
|
|
224
|
-
};
|
|
225
|
-
contextMetadata?: MCPContextMetadata;
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
export type { CustomLogEntry, JSONRPCMessage, JSONRPCRequest, JSONRPCResponse, MCPContextMetadata, MCPSpanData, MessageDirection, PairedSpanInput, RequestOnlySpanInput, ResponseOnlySpanInput, SessionContext, SessionContextStore, SpanAttributes, TelemetryOptions };
|
package/dist/sdk/index.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(){return S}function r(){return q}function t(){return N||"unknown"}async function s(){if(I)try{await I.shutdown(),I=null,S=null,w=!1,q=null,N=null}catch(e){console.error("[MCP Logger] Error shutting down telemetry:",e)}}function o(e,r=2e5){try{const t=JSON.stringify(e);return t.length>r?t.slice(0,r)+"... (truncated)":t}catch(e){return null}}function n(e,r){return e.startsWith("resources/")?{type:e.split("/")[1],uri:r?.uri||r?.path||r?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:r?.name||r?.promptId}:"tools/call"===e?{type:"tool",uri:r?.name}:r?.resourceType&&r?.resourceUri?{type:r.resourceType,uri:r.resourceUri}:{type:void 0,uri:void 0}}function i(e,r,t,s,o){const i=function(e,r){const t=r;if(t){const e=t["user-agent"]||t["User-Agent"];if(e){const r=e.match(/^([^\/]+)\/([^\s]+)/);if(r)return{name:r[1],version:r[2]}}}return{name:void 0,version:void 0}}(0,o),c=function(e){if(!M.has(e)){const r=y();M.set(e,r)}return M.get(e)}(`${i.name||"unknown"}-${i.version||"0"}`),a=function(e,r){const t=`${e}-${r}`;return O.has(t)||O.set(t,"conv-"+ ++R),O.get(t)}(c,e),m=function(e,r){return e?.userId||e?.user_id?e.userId||e.user_id:r?r["x-user-id"]||r["X-User-Id"]:void 0}(r,o),u=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(r),p=n(e,r);p.uri&&function(e){const r=(L.get(e)||0)+1;L.set(e,r)}(p.uri);const l=function(e,r){return void 0!==e?.cost?e.cost:void 0!==r?.cost?r.cost:void 0}(r,t),d={};return c&&(d.sessionId=c),a&&(d.conversationId=a),m&&(d.userId=m),i.name&&(d.clientName=i.name),i.version&&(d.clientVersion=i.version),u&&(d.permissionLevel=u),void 0!==l&&(d.cost=l),d}function c(s){const c=e();if(!c)return void console.error("[MCP Logger] Tracer not initialized, cannot create span");const a="mcp."+s.method;c.startActiveSpan(a,e=>{try{const c={"mcp.source":s.source,"mcp.transport":s.transport,"mcp.request.id":s.request.id+"","mcp.request.method":s.method,"mcp.request.timestamp":s.request.timestamp,"mcp.request.params":o(s.request.params)||"{}","mcp.request.params.size":JSON.stringify(s.request.params||{}).length,"mcp.response.id":s.request.id+"","mcp.response.timestamp":s.response.timestamp,"mcp.duration_ms":s.duration};if("tools/call"===s.method&&s.request.params){const e=s.request.params.name,r=s.request.params.arguments;if(e&&(c["mcp.tool.name"]=e),r){const e=o(r);e&&(c["mcp.tool.arguments"]=e,c["mcp.tool.arguments.size"]=JSON.stringify(r).length)}}if(void 0!==s.response.result){const e=o(s.response.result);e&&(c["mcp.response.result"]=e,c["mcp.response.result.size"]=JSON.stringify(s.response.result).length)}if(s.request.headers){const e=o(s.request.headers);e&&(c["mcp.headers"]=e,c["mcp.headers.size"]=JSON.stringify(s.request.headers).length)}if("cli"===s.source){const e=r();e&&(c["mcp.cli"]=JSON.stringify({command:e.command,args:e.args,env:e.env}));const s=t();c["mcp.server.version"]=s}const a=s.contextMetadata||i(s.method,s.request.params,s.response.result,0,s.request.headers);a.sessionId&&(c["mcp.session.id"]=a.sessionId),a.conversationId&&(c["mcp.conversation.id"]=a.conversationId),a.sessionId&&a.conversationId&&(c["mcp.trace.id"]=`${a.sessionId}:${a.conversationId}`),a.userId&&(c["mcp.user.id"]=a.userId),a.clientName&&(c["mcp.client.name"]=a.clientName),a.clientVersion&&(c["mcp.client.version"]=a.clientVersion),a.permissionLevel&&(c["mcp.permission.level"]=a.permissionLevel),void 0!==a.cost&&(c["mcp.cost"]=a.cost);const u=function(e,r){const t=n(e,r);if(!t.uri)return{};const s=L.get(t.uri)||0;return{resourceType:t.type,resourceUri:t.uri,resourceAccessCount:s}}(s.method,s.request.params);if(u.resourceType&&(c["mcp.resource.type"]=u.resourceType),u.resourceUri&&(c["mcp.resource.uri"]=u.resourceUri),u.resourceAccessCount&&(c["mcp.resource.access_count"]=u.resourceAccessCount),s.customEvents&&s.customEvents.length>0&&(c["mcp.events"]=JSON.stringify(s.customEvents),c["mcp.events.count"]=s.customEvents.length,s.customEvents.forEach(r=>{e.addEvent("custom."+(r.level||"info"),{message:r.message,metadata:JSON.stringify(r.metadata||{}),timestamp:r.timestamp||Date.now()})})),s.response.error){let r;c["mcp.error"]=!0,r=s.response.error instanceof Error?s.response.error.message:"string"==typeof s.response.error?s.response.error:o(s.response.error)||"Unknown error",c["mcp.error.message"]=r,s.response.error instanceof Error&&e.recordException(s.response.error),e.setStatus({code:m.ERROR,message:r})}else e.setStatus({code:m.OK});!function(e,r){for(const[t,s]of Object.entries(r))null!=s&&e.setAttribute(t,s)}(e,c)}catch(r){console.error("[MCP Logger] Error creating paired span:",r),e.setStatus({code:m.ERROR,message:r+""})}finally{e.end()}})}import{trace as a,SpanStatusCode as m,context as u}from"@opentelemetry/api";import{NodeSDK as p}from"@opentelemetry/sdk-node";import{OTLPTraceExporter as l}from"@opentelemetry/exporter-trace-otlp-http";import{Resource as d}from"@opentelemetry/resources";import{readFileSync as g}from"fs";import{fileURLToPath as v}from"url";import{dirname as f,join as h}from"path";import{ulid as y}from"ulid";const E={ENDPOINT:"https://api.awarecorp.io/traces",SDK_VERSION:function(){try{const e=v(import.meta.url),r=f(e),t=h(r,"..","..","package.json");return JSON.parse(g(t,"utf-8")).version||"1.0.0"}catch(e){return console.error("[MCP Logger] Failed to read package version:",e),"1.0.0"}}(),SERVICE_NAME_PREFIX:"mcp-server"};let I=null,S=null,w=!1,q=null,N=null;const M=new Map,O=new Map;let R=0;const L=new Map,C=Symbol("mcp-logger.customEvents"),b=Object.assign(function(e,r){if(!r.apiKey)throw Error("[mcp-logger] apiKey is required");if(!e)throw Error("[mcp-logger] server instance is required");!function(e){if(w)return e.debug&&console.error("[MCP Logger] Telemetry already initialized, returning existing tracer"),S;const r=e.endpoint||E.ENDPOINT,t=e.serviceName||`${E.SERVICE_NAME_PREFIX}-${Math.random().toString(36).slice(2,8)}`;e.debug&&(console.error("[MCP Logger] Initializing telemetry..."),console.error("[MCP Logger] Endpoint: "+r),console.error("[MCP Logger] Service: "+t)),I=new p({resource:new d({"service.name":t,"service.version":E.SDK_VERSION}),traceExporter:new l({url:r,headers:{"x-api-key":e.apiKey}})}),I.start(),S=a.getTracer("mcp-logger",E.SDK_VERSION),w=!0,e.debug&&console.error("[MCP Logger] Telemetry initialized successfully");const o=async()=>{e.debug&&console.error("[MCP Logger] Shutting down telemetry..."),await s()};process.once("SIGTERM",o),process.once("SIGINT",o)}(r),function(e,r){const t=e.setRequestHandler.bind(e);e.setRequestHandler=function(e,s){const o=e.shape?.method,n=o?._def?.value||"unknown";return r.debug&&console.log("[mcp-logger] Instrumenting handler: "+n),t(e,async(e,t)=>{const o=Date.now(),a=`${n}-${o}-${Math.random().toString(36).slice(2,8)}`,m=[],p=u.active().setValue(C,m);try{const l=await u.with(p,async()=>await s(e,t)),d=Date.now(),g=i(n,e.params,l,0,void 0);return c({method:n,source:"sdk",transport:"stdio",request:{id:a,timestamp:o,params:e.params},response:{timestamp:d,result:l},duration:d-o,customEvents:m.length>0?m:void 0,contextMetadata:g}),r.debug&&console.log(`[mcp-logger] Request completed (${d-o}ms):`,{method:n,customEvents:m.length}),l}catch(t){const s=Date.now(),u=i(n,e.params,void 0,0,void 0);throw c({method:n,source:"sdk",transport:"stdio",request:{id:a,timestamp:o,params:e.params},response:{timestamp:s,error:t},duration:s-o,customEvents:m.length>0?m:void 0,contextMetadata:u}),r.debug&&console.error("[mcp-logger] Request failed:",t),t}})},r.debug&&console.log("[mcp-logger] Server instrumentation complete")}(e,r),r.debug&&console.log("[mcp-logger] β Initialization complete")},{addLog(e){const r=u.active().getValue(C);if(!r)return void console.warn("[mcp-logger] addLog called outside of handler context");const t={level:e.level||"info",message:e.message,metadata:e.metadata,timestamp:e.timestamp||Date.now()};r.push(t);const s=a.getSpan(u.active());s&&s.addEvent("custom."+t.level,{message:t.message,metadata:JSON.stringify(t.metadata||{}),timestamp:t.timestamp})},async shutdown(){await s()}});export{b as trace};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
function e(e,t,o,r,n){const s=function(e){if(!p.has(e)){const t=a();p.set(e,t)}return p.get(e)}("unknown-0"),i=function(e,t){const o=`${e}-${t}`;return m.has(o)||m.set(o,"conv-"+ ++l),m.get(o)}(s,e),c=function(e){if(e?.userId||e?.user_id)return e.userId||e.user_id}(t),u=function(e){if(e?.permission||e?.permissionLevel)return e.permission||e.permissionLevel}(t),g=function(e,t){return e.startsWith("resources/")?{type:e.split("/")[1],uri:t?.uri||t?.path||t?.resource}:e.startsWith("prompts/")?{type:"prompt",uri:t?.name||t?.promptId}:"tools/call"===e?{type:"tool",uri:t?.name}:t?.resourceType&&t?.resourceUri?{type:t.resourceType,uri:t.resourceUri}:{type:void 0,uri:void 0}}(e,t);g.uri&&function(e){const t=(d.get(e)||0)+1;d.set(e,t)}(g.uri);const f=function(e,t){return void 0!==e?.cost?e.cost:void 0!==t?.cost?t.cost:void 0}(t,o),v={};return s&&(v.sessionId=s),i&&(v.conversationId=i),c&&(v.userId=c),u&&(v.permissionLevel=u),void 0!==f&&(v.cost=f),v}function t(e){console.error("[MCP Logger] Tracer not initialized, cannot create span")}function o(o,r){const s=o.setRequestHandler.bind(o);o.setRequestHandler=function(o,i){const c=o.shape?.method,u=c?._def?.value||"unknown";return r.debug&&console.log("[mcp-logger] Instrumenting handler: "+u),s(o,async(o,s)=>{const c=Date.now(),a=(Math.random().toString(36).slice(2,8),[]),p=n.active().setValue(g,a);try{const m=await n.with(p,async()=>await i(o,s)),l=Date.now();return e(u,o.params,m),t(o.params),r.debug&&console.log(`[mcp-logger] Request completed (${l-c}ms):`,{method:u,customEvents:a.length}),m}catch(n){throw e(u,o.params,void 0),t(o.params),r.debug&&console.error("[mcp-logger] Request failed:",n),n}})},r.debug&&console.log("[mcp-logger] Server instrumentation complete")}function r(){return n.active().getValue(g)}import{context as n}from"@opentelemetry/api";import"@opentelemetry/sdk-node";import"@opentelemetry/exporter-trace-otlp-http";import"@opentelemetry/resources";import{readFileSync as s}from"fs";import{fileURLToPath as i}from"url";import{dirname as c,join as u}from"path";import{ulid as a}from"ulid";!function(){try{const e=i(import.meta.url),t=c(e),o=u(t,"..","..","package.json");return JSON.parse(s(o,"utf-8")).version||"1.0.0"}catch(e){return console.error("[MCP Logger] Failed to read package version:",e),"1.0.0"}}();const p=new Map,m=new Map;let l=0;const d=new Map,g=Symbol("mcp-logger.customEvents");export{r as getCustomEventsFromContext,o as instrumentMCPServer};
|
package/dist/sdk/types.d.ts
DELETED
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
2
|
-
import { ZodObject, ZodLiteral } from 'zod';
|
|
3
|
-
import { Request, Result } from '@modelcontextprotocol/sdk/types.js';
|
|
4
|
-
|
|
5
|
-
/**
|
|
6
|
-
* κ³΅ν΅ νμ
μ μ
|
|
7
|
-
*/
|
|
8
|
-
/**
|
|
9
|
-
* ν
λ λ©νΈλ¦¬ μ΄κΈ°ν μ΅μ
|
|
10
|
-
*/
|
|
11
|
-
interface TelemetryOptions {
|
|
12
|
-
/**
|
|
13
|
-
* API Key for authentication (νμ)
|
|
14
|
-
*/
|
|
15
|
-
apiKey: string;
|
|
16
|
-
/**
|
|
17
|
-
* μλΉμ€ μ΄λ¦ (μ΅μ
)
|
|
18
|
-
* μ§μ νμ§ μμΌλ©΄ μλμΌλ‘ 'mcp-server-{random}' νμμΌλ‘ μμ±
|
|
19
|
-
*/
|
|
20
|
-
serviceName?: string;
|
|
21
|
-
/**
|
|
22
|
-
* 컀μ€ν
OTLP μλν¬μΈνΈ (μ΅μ
)
|
|
23
|
-
* κΈ°λ³Έκ°: CONFIG.ENDPOINT
|
|
24
|
-
*/
|
|
25
|
-
endpoint?: string;
|
|
26
|
-
/**
|
|
27
|
-
* λλ²κ·Έ λ‘κ·Έ νμ±ν (μ΅μ
)
|
|
28
|
-
*/
|
|
29
|
-
debug?: boolean;
|
|
30
|
-
}
|
|
31
|
-
/**
|
|
32
|
-
* 컀μ€ν
λ‘κ·Έ μνΈλ¦¬
|
|
33
|
-
*/
|
|
34
|
-
interface CustomLogEntry$1 {
|
|
35
|
-
/**
|
|
36
|
-
* λ‘κ·Έ λ 벨
|
|
37
|
-
*/
|
|
38
|
-
level?: 'info' | 'warn' | 'error';
|
|
39
|
-
/**
|
|
40
|
-
* λ‘κ·Έ λ©μμ§
|
|
41
|
-
*/
|
|
42
|
-
message: string;
|
|
43
|
-
/**
|
|
44
|
-
* μΆκ° λ©νλ°μ΄ν° (μμ νμ)
|
|
45
|
-
*/
|
|
46
|
-
metadata?: Record<string, any>;
|
|
47
|
-
/**
|
|
48
|
-
* νμμ€ν¬ν (μλ μμ± κ°λ₯)
|
|
49
|
-
*/
|
|
50
|
-
timestamp?: number;
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
/**
|
|
54
|
-
* SDK νμ
μ μ
|
|
55
|
-
*/
|
|
56
|
-
|
|
57
|
-
/**
|
|
58
|
-
* Trace μ΅μ
|
|
59
|
-
*/
|
|
60
|
-
interface TraceOptions extends TelemetryOptions {
|
|
61
|
-
}
|
|
62
|
-
/**
|
|
63
|
-
* Custom Log Entry (re-export from core)
|
|
64
|
-
*/
|
|
65
|
-
type CustomLogEntry = CustomLogEntry$1;
|
|
66
|
-
/**
|
|
67
|
-
* MCP JSON-RPC Request νμ
|
|
68
|
-
*/
|
|
69
|
-
type MCPRequest = Request;
|
|
70
|
-
/**
|
|
71
|
-
* MCP Result νμ
|
|
72
|
-
*/
|
|
73
|
-
type MCPResult = Result;
|
|
74
|
-
/**
|
|
75
|
-
* MCP Request Schema νμ
|
|
76
|
-
*/
|
|
77
|
-
type MCPRequestSchema = ZodObject<{
|
|
78
|
-
method: ZodLiteral<string>;
|
|
79
|
-
}>;
|
|
80
|
-
/**
|
|
81
|
-
* Request Handler Extra νμ
|
|
82
|
-
*/
|
|
83
|
-
interface RequestHandlerExtra {
|
|
84
|
-
signal: AbortSignal;
|
|
85
|
-
}
|
|
86
|
-
/**
|
|
87
|
-
* MCP Server νμ
(μ¬export)
|
|
88
|
-
*/
|
|
89
|
-
type MCPServer = Server;
|
|
90
|
-
|
|
91
|
-
export type { CustomLogEntry, MCPRequest, MCPRequestSchema, MCPResult, MCPServer, RequestHandlerExtra, TraceOptions };
|