traceAI-mcp-use 0.1.0__tar.gz
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.
- traceai_mcp_use-0.1.0/PKG-INFO +399 -0
- traceai_mcp_use-0.1.0/README.md +366 -0
- traceai_mcp_use-0.1.0/pyproject.toml +45 -0
- traceai_mcp_use-0.1.0/traceai_mcp_use/__init__.py +13 -0
- traceai_mcp_use-0.1.0/traceai_mcp_use/_callback.py +1113 -0
- traceai_mcp_use-0.1.0/traceai_mcp_use/_text.py +245 -0
- traceai_mcp_use-0.1.0/traceai_mcp_use/py.typed +0 -0
- traceai_mcp_use-0.1.0/traceai_mcp_use/version.py +1 -0
|
@@ -0,0 +1,399 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: traceAI-mcp-use
|
|
3
|
+
Version: 0.1.0
|
|
4
|
+
Summary: OpenTelemetry tracing for mcp-use agents: one span per agent run, LLM call and tool call
|
|
5
|
+
License: Apache-2.0
|
|
6
|
+
Keywords: traceai,futureagi,opentelemetry,tracing,observability,llm,mcp-use
|
|
7
|
+
Author: Future AGI
|
|
8
|
+
Author-email: no-reply@futureagi.com
|
|
9
|
+
Requires-Python: >=3.11,<3.14
|
|
10
|
+
Classifier: Development Status :: 3 - Alpha
|
|
11
|
+
Classifier: Framework :: OpenTelemetry
|
|
12
|
+
Classifier: Framework :: OpenTelemetry :: Instrumentations
|
|
13
|
+
Classifier: Intended Audience :: Developers
|
|
14
|
+
Classifier: License :: OSI Approved :: Apache Software License
|
|
15
|
+
Classifier: Programming Language :: Python
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
20
|
+
Classifier: Programming Language :: Python :: 3 :: Only
|
|
21
|
+
Classifier: Topic :: Software Development :: Libraries :: Python Modules
|
|
22
|
+
Classifier: Topic :: System :: Monitoring
|
|
23
|
+
Requires-Dist: fi-instrumentation-otel (>=1.1.0)
|
|
24
|
+
Requires-Dist: langchain-core (>=1.0.0,<2)
|
|
25
|
+
Requires-Dist: mcp-use (>=1.7.1,<2)
|
|
26
|
+
Project-URL: Changelog, https://github.com/future-agi/traceAI/blob/dev/python/frameworks/mcp-use/CHANGELOG.md
|
|
27
|
+
Project-URL: Documentation, https://docs.futureagi.com/docs/tracing
|
|
28
|
+
Project-URL: Homepage, https://futureagi.com
|
|
29
|
+
Project-URL: Issues, https://github.com/future-agi/traceAI/issues
|
|
30
|
+
Project-URL: Repository, https://github.com/future-agi/traceAI/tree/dev/python/frameworks/mcp-use
|
|
31
|
+
Description-Content-Type: text/markdown
|
|
32
|
+
|
|
33
|
+
# traceAI-mcp-use
|
|
34
|
+
|
|
35
|
+
OpenTelemetry tracing for [mcp-use](https://pypi.org/project/mcp-use/)
|
|
36
|
+
agents (`mcp_use.MCPAgent`), sent to Future AGI.
|
|
37
|
+
|
|
38
|
+
`FutureAGICallback` is a LangChain callback handler. You pass it to the
|
|
39
|
+
agent with `MCPAgent(..., callbacks=[...])`. It records one span for each
|
|
40
|
+
agent run, each LLM call and each tool call. It patches nothing, imports
|
|
41
|
+
neither `langfuse` nor `traceai_mcp`, and sets no environment variables.
|
|
42
|
+
|
|
43
|
+
This package traces the agent loop. [`traceAI-mcp`](../mcp) (`traceai_mcp`)
|
|
44
|
+
works at the MCP transport level and is a different layer: a green
|
|
45
|
+
transport test does not show the agent run, its model calls or its tool
|
|
46
|
+
calls. See [Other tracing in the same process](#other-tracing-in-the-same-process).
|
|
47
|
+
|
|
48
|
+
## Installation
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pip install traceAI-mcp-use
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
It accepts `mcp-use>=1.7.1,<2`, `langchain-core>=1.0.0,<2` and
|
|
55
|
+
`fi-instrumentation-otel>=1.1.0`, on Python `>=3.11,<3.14` (mcp-use itself
|
|
56
|
+
requires 3.11). The suite runs with mcp-use 1.7.1 (the latest release on
|
|
57
|
+
2026-10-16) on Python 3.11, 3.12 and 3.13, and was run end to end against a
|
|
58
|
+
real model and a real stdio MCP server with mcp-use 1.7.1, langchain-core
|
|
59
|
+
1.6.12, langchain-openai 1.7.2 and langgraph 1.2.16.
|
|
60
|
+
|
|
61
|
+
## Usage
|
|
62
|
+
|
|
63
|
+
```python
|
|
64
|
+
from fi_instrumentation import register
|
|
65
|
+
from fi_instrumentation.fi_types import ProjectType
|
|
66
|
+
from mcp_use import MCPAgent, MCPClient
|
|
67
|
+
from traceai_mcp_use import FutureAGICallback
|
|
68
|
+
|
|
69
|
+
trace_provider = register(project_type=ProjectType.OBSERVE, project_name="mcp-use-agent")
|
|
70
|
+
|
|
71
|
+
client = MCPClient.from_dict({"mcpServers": {"calculator": {"command": "python", "args": ["server.py"]}}})
|
|
72
|
+
agent = MCPAgent(
|
|
73
|
+
llm=llm, # any LangChain chat model
|
|
74
|
+
client=client,
|
|
75
|
+
callbacks=[FutureAGICallback(tracer_provider=trace_provider)],
|
|
76
|
+
)
|
|
77
|
+
result = await agent.run("What is 2 + 3?")
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
Pass the provider `register()` returns: `register()` does not set the
|
|
81
|
+
global provider unless you ask it to, and without `tracer_provider` the
|
|
82
|
+
callback uses the global one. One callback can serve many agents and
|
|
83
|
+
concurrent runs. See [`examples/agent_with_tools.py`](examples/agent_with_tools.py).
|
|
84
|
+
|
|
85
|
+
`MCPAgent.run()`, `stream()` and `stream_events()` are all traced. The
|
|
86
|
+
Python `MCPAgent` is async only.
|
|
87
|
+
|
|
88
|
+
## Spans
|
|
89
|
+
|
|
90
|
+
| Span | Name | `gen_ai.span.kind` | One per |
|
|
91
|
+
|---|---|---|---|
|
|
92
|
+
| Agent | `mcp_use.agent` | `AGENT` | `run()`, `stream()` or `stream_events()` call |
|
|
93
|
+
| LLM | `chat <model>` (`text_completion <model>` for completion models; `chat` when no model name is reported) | `LLM` | model call |
|
|
94
|
+
| Tool | `execute_tool <tool>` | `TOOL` | tool call |
|
|
95
|
+
|
|
96
|
+
The LLM and tool spans are children of the agent span. In the LangChain
|
|
97
|
+
run tree, LangGraph's `model` and `tools` nodes sit between them; graph
|
|
98
|
+
nodes and middleware are not spans, so a tool span is a sibling of the LLM
|
|
99
|
+
spans, not a child of the LLM call that requested it. The agent span is a
|
|
100
|
+
child of the span that is current when the run starts, or a root span.
|
|
101
|
+
|
|
102
|
+
A streamed completion is one LLM span, ended when the stream ends. Each
|
|
103
|
+
token LangChain reports is a `mcp_use.llm.chunk` event carrying only its
|
|
104
|
+
index (`mcp_use.llm.chunk.index`, never the text), for the first 128
|
|
105
|
+
tokens; `mcp_use.llm.chunk_count` holds the exact number.
|
|
106
|
+
|
|
107
|
+
The spans are not made current while their run executes, as in
|
|
108
|
+
`traceAI-langchain`: a span another instrumentation starts inside a tool
|
|
109
|
+
call (for example an HTTP client span) is not a child of the tool span.
|
|
110
|
+
|
|
111
|
+
## Span attributes
|
|
112
|
+
|
|
113
|
+
| Attribute | Span | Value |
|
|
114
|
+
|---|---|---|
|
|
115
|
+
| `gen_ai.operation.name` | all | `invoke_agent`, `chat`, `text_completion` or `execute_tool` |
|
|
116
|
+
| `mcp_use.agent.llm_call_count`, `mcp_use.agent.tool_call_count`, `mcp_use.agent.tool_error_count` | agent | Model calls, tool calls and failed tool calls in the run |
|
|
117
|
+
| `gen_ai.request.model` | LLM | From LangChain's `ls_model_name`, else the invocation `model` / `model_name` / `model_id` |
|
|
118
|
+
| `gen_ai.provider.name`, `gen_ai.request.temperature`, `gen_ai.request.max_tokens` | LLM | From LangChain's `ls_provider`, `ls_temperature`, `ls_max_tokens` |
|
|
119
|
+
| `gen_ai.response.model`, `gen_ai.response.finish_reasons` | LLM | From the response metadata |
|
|
120
|
+
| `gen_ai.usage.input_tokens`, `gen_ai.usage.output_tokens`, `gen_ai.usage.total_tokens`, `gen_ai.usage.cache_read_tokens` | LLM | From the message's `usage_metadata` (or the provider's `token_usage`) |
|
|
121
|
+
| `mcp_use.llm.input_message_count` | LLM | Messages sent to the model |
|
|
122
|
+
| `mcp_use.llm.tool_call_count` | LLM | Tool calls the model asked for |
|
|
123
|
+
| `mcp_use.llm.chunk_count` | LLM | Streamed tokens, when streamed |
|
|
124
|
+
| `gen_ai.tool.name`, `gen_ai.tool.call.id` | tool | The tool and the model's tool-call id |
|
|
125
|
+
| `mcp_use.tool.error_type` | tool | Error type, when the tool's failure came back as its result |
|
|
126
|
+
| `mcp_use.cancelled`, `mcp_use.incomplete` | any | See [Errors and cancellation](#errors-and-cancellation) |
|
|
127
|
+
|
|
128
|
+
A value the callback is not given is omitted, never written as 0. Content
|
|
129
|
+
is recorded too, unless a `TraceConfig` hide flag turns it off (see
|
|
130
|
+
[Privacy](#privacy)):
|
|
131
|
+
|
|
132
|
+
| Attribute | Span | Value |
|
|
133
|
+
|---|---|---|
|
|
134
|
+
| `input.value` | agent | The last user message of the run's input |
|
|
135
|
+
| `output.value` | agent | The final answer (the last assistant message without tool calls) |
|
|
136
|
+
| `gen_ai.input.messages.<i>.message.role` / `.content` / `.tool_calls.<j>.tool_call.*` | LLM | The 32 most recent input messages |
|
|
137
|
+
| `gen_ai.output.messages.<i>.message.*` | LLM | The model's reply, with up to 16 tool calls (name, id, arguments) |
|
|
138
|
+
| `input.value`, `output.value` | LLM | The last input message's text and the reply's text |
|
|
139
|
+
| `gen_ai.tool.call.arguments`, `input.value` | tool | The arguments, as JSON |
|
|
140
|
+
| `gen_ai.tool.call.result`, `output.value` | tool | The tool's result text |
|
|
141
|
+
|
|
142
|
+
Spans come from an `fi_instrumentation.FITracer`, so the attributes of
|
|
143
|
+
`using_session`, `using_user`, `using_metadata`, `using_tags` and
|
|
144
|
+
`using_attributes` (`session.id`, `user.id`, `metadata`, `tag.tags`) are
|
|
145
|
+
set on every span of a run started inside them:
|
|
146
|
+
|
|
147
|
+
```python
|
|
148
|
+
from fi_instrumentation import using_metadata, using_session, using_tags, using_user
|
|
149
|
+
|
|
150
|
+
with using_session("session-1"), using_user("user-1"), using_metadata({"tenant": "t1"}), using_tags(["beta"]):
|
|
151
|
+
await agent.run("What is 2 + 3?")
|
|
152
|
+
```
|
|
153
|
+
|
|
154
|
+
The Python `MCPAgent` has no `set_metadata` or `set_tags` (the TypeScript
|
|
155
|
+
agent does); use these context managers instead.
|
|
156
|
+
|
|
157
|
+
## Privacy
|
|
158
|
+
|
|
159
|
+
Content follows `TraceConfig`, like every traceAI instrumentor: prompts,
|
|
160
|
+
messages, model output, tool arguments, tool results and error messages are
|
|
161
|
+
recorded by default, and the standard hide flags turn them off. There is no
|
|
162
|
+
separate switch in this package.
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
export FI_HIDE_INPUTS=true # prompts, input messages, tool arguments
|
|
166
|
+
export FI_HIDE_OUTPUTS=true # model output, output messages, tool results
|
|
167
|
+
```
|
|
168
|
+
|
|
169
|
+
or `FutureAGICallback(tracer_provider=..., config=TraceConfig(hide_inputs=True, hide_outputs=True))`.
|
|
170
|
+
With both flags on, spans carry names, kinds, the model and provider,
|
|
171
|
+
request parameters, usage, finish reasons, counts, the tool-call id,
|
|
172
|
+
statuses and exception types; `input.value` and `output.value` are
|
|
173
|
+
`__REDACTED__`.
|
|
174
|
+
|
|
175
|
+
Never recorded, whatever the flags:
|
|
176
|
+
|
|
177
|
+
- stack traces. The `exception` event has `exception.type` and, when
|
|
178
|
+
content is on, `exception.message`; never `exception.stacktrace`. mcp-use
|
|
179
|
+
sends a failed tool call back to the model as `format_error()`'s dict,
|
|
180
|
+
whose `stack` is a full traceback; in that tool message the trace is
|
|
181
|
+
replaced with `[stack trace removed]` and the rest of the JSON is kept.
|
|
182
|
+
Any other text loses everything from `Traceback (most recent call last):`
|
|
183
|
+
on;
|
|
184
|
+
- absolute local paths (`/Users/...`, `/home/...`, `/tmp/...`, `C:\...`
|
|
185
|
+
and similar), replaced with `[path]`;
|
|
186
|
+
- this machine's user name and host name, replaced with `[user]` and
|
|
187
|
+
`[host]` (names of 4 characters or more that are not generic, such as
|
|
188
|
+
`root` or `app`).
|
|
189
|
+
|
|
190
|
+
```python
|
|
191
|
+
FutureAGICallback(
|
|
192
|
+
tracer_provider=trace_provider,
|
|
193
|
+
config=TraceConfig(hide_inputs=True), # optional; default reads FI_HIDE_* from the environment
|
|
194
|
+
redact=["my-mcp-server-token"], # extra secret strings to remove
|
|
195
|
+
)
|
|
196
|
+
```
|
|
197
|
+
|
|
198
|
+
`redact` must be an iterable of strings; anything else raises `TypeError`.
|
|
199
|
+
|
|
200
|
+
Secrets are removed from every text the callback writes, including names
|
|
201
|
+
and ids, with content on or hidden. They are replaced by `[redacted]`:
|
|
202
|
+
|
|
203
|
+
- the strings passed as `redact=`;
|
|
204
|
+
- the value (8 characters or longer) of every environment variable whose
|
|
205
|
+
name contains `KEY`, `SECRET`, `TOKEN`, `PASSWORD`, `PASSWD`,
|
|
206
|
+
`CREDENTIAL` or `AUTH`, read each time a text is written. That covers
|
|
207
|
+
provider keys such as `OPENAI_API_KEY` and `FI_API_KEY`/`FI_SECRET_KEY`;
|
|
208
|
+
- `Bearer`/`Basic` credentials, `sk-`/`pk-`/`rk-` style keys and
|
|
209
|
+
`api_key=`, `token:`, `password=` or `Authorization:` assignments.
|
|
210
|
+
|
|
211
|
+
The callback never reads LangChain's serialized model payload (which can
|
|
212
|
+
include the model's repr, and so its key) or the invocation parameters
|
|
213
|
+
other than the model name.
|
|
214
|
+
|
|
215
|
+
`TraceConfig` settings apply. Pass `config=TraceConfig(...)` or set the
|
|
216
|
+
environment variables before creating the callback:
|
|
217
|
+
|
|
218
|
+
| Setting | Effect |
|
|
219
|
+
|---|---|
|
|
220
|
+
| `hide_inputs` / `FI_HIDE_INPUTS=true` | `input.value` is `__REDACTED__`; input messages and tool-call arguments (on tool spans and in model replies) are dropped. Every other text of the run has each input it has seen replaced with `__REDACTED__`: the user messages, the messages sent to the model, and each string value of each tool call's arguments. Error messages are dropped: the status and the `exception` event carry the exception type only. |
|
|
221
|
+
| `hide_outputs` / `FI_HIDE_OUTPUTS=true` | `output.value` is `__REDACTED__`; output messages and tool results are dropped. Model replies and tool results sent back to the model as input messages (later in the same run, or from earlier turns; see below) keep their role but lose their content and tool-call arguments, and an LLM span whose last input message is one of them has `input.value` `__REDACTED__`. Every other text of the run has each output it has seen (model replies, their tool-call arguments, tool results, earlier turns' included) replaced with `__REDACTED__`. Error messages are dropped: the status and the `exception` event carry the exception type only. |
|
|
222
|
+
| `hide_input_messages`, `hide_output_messages`, `hide_input_text`, `hide_output_text` (`FI_HIDE_INPUT_MESSAGES`, ...) | Applied by `FITracer` to the `gen_ai.input.messages.*` / `gen_ai.output.messages.*` attributes, as for every traceAI instrumentor. |
|
|
223
|
+
| `pii_redaction` / `FI_PII_REDACTION=true` | Emails, phone numbers, SSNs, card numbers, IPv4 addresses and `sk-`/`pk-` keys become tokens such as `<EMAIL_ADDRESS>` in every recorded text: attributes, the error status and the `exception` event. It runs after secrets (and hidden inputs/outputs) are removed and before the size caps. |
|
|
224
|
+
|
|
225
|
+
`config` must be a `fi_instrumentation.TraceConfig`; anything else raises
|
|
226
|
+
`TypeError`. Other `TraceConfig` fields act only through `FITracer`'s
|
|
227
|
+
attribute masking.
|
|
228
|
+
|
|
229
|
+
mcp-use's own console logging is not part of the trace and is not changed
|
|
230
|
+
by these flags: at its default level it prints query previews and tool
|
|
231
|
+
results (INFO), and a failed tool call's formatted error with its stack
|
|
232
|
+
trace (ERROR, `mcp_use/errors/error_formatting.py`). `Logger.set_debug(0)`
|
|
233
|
+
(`from mcp_use import Logger`) hides the INFO lines;
|
|
234
|
+
`logging.getLogger("mcp_use").setLevel(logging.CRITICAL)` also hides the
|
|
235
|
+
ERROR line.
|
|
236
|
+
|
|
237
|
+
Multi-turn conversations: `MCPAgent` keeps memory by default
|
|
238
|
+
(`memory_enabled=True`) and sends the earlier turns, model replies and tool
|
|
239
|
+
results included, back to the model as input on the next `run()`,
|
|
240
|
+
`stream()` or `stream_events()` call (`mcp_use/agents/mcpagent.py:76`,
|
|
241
|
+
`:724-732`, `:879-880`, `:981-983`); `external_history` does the same.
|
|
242
|
+
Each call is its own agent span. Under `hide_outputs`, every assistant- or
|
|
243
|
+
tool-role message (any role other than user and system) among a run's
|
|
244
|
+
input messages counts as an output: its content and tool-call arguments
|
|
245
|
+
are dropped from the input messages and removed from every other text of
|
|
246
|
+
that run, error text included. The callback reads them when the run
|
|
247
|
+
starts, before it writes any of the run's spans. This is
|
|
248
|
+
tested over three turns on one agent through `run()`, `stream()`,
|
|
249
|
+
`stream_events()` and `external_history`, and on the export. User messages
|
|
250
|
+
of earlier turns are inputs: they are recorded unless `hide_inputs` is on.
|
|
251
|
+
The texts a run remembers include its replayed history, so in a long
|
|
252
|
+
conversation the per-run limit below is reached sooner.
|
|
253
|
+
|
|
254
|
+
The hide flags match each text verbatim, and also in its Python-repr and
|
|
255
|
+
JSON-quoted forms; a copy that was escaped differently, cut or reworded
|
|
256
|
+
stays. Texts shorter than 3 characters are only matched in quoted form,
|
|
257
|
+
and non-string argument values (numbers, booleans) are not matched. With a
|
|
258
|
+
hide flag on, the callback remembers at most 2048 text forms or about 4
|
|
259
|
+
million characters per run; past that it fails closed and records no
|
|
260
|
+
content for the rest of that run (no messages, arguments, results or
|
|
261
|
+
error messages).
|
|
262
|
+
|
|
263
|
+
## Errors and cancellation
|
|
264
|
+
|
|
265
|
+
A failed tool call is a tool span with status ERROR and one `exception`
|
|
266
|
+
event. mcp-use 1.7.1 does not raise for a failed MCP call: it returns a
|
|
267
|
+
formatted error to the model as the tool's result
|
|
268
|
+
(`mcp_use/agents/adapters/langchain_adapter.py:181-206`). The callback
|
|
269
|
+
recognises that result (an object with mcp-use's `error`, `details`,
|
|
270
|
+
`stack` and `code` keys and a `tool` key equal to the tool's name; a tool's
|
|
271
|
+
own result with those keys but no matching `tool` is a result), takes the
|
|
272
|
+
error type from it
|
|
273
|
+
(`mcp_use.tool.error_type`) and counts it in
|
|
274
|
+
`mcp_use.agent.tool_error_count`. A tool call LangChain reports as failed
|
|
275
|
+
(for example arguments that fail validation) is recorded the same way,
|
|
276
|
+
with the exception's type. Either way the model sees the error and the run
|
|
277
|
+
usually goes on, so the agent span ends OK when the run returns an answer.
|
|
278
|
+
|
|
279
|
+
When the run itself fails (for example the model call raises), the LLM
|
|
280
|
+
span and the agent span end with status ERROR and an `exception` event,
|
|
281
|
+
and the exception reaches your code unchanged.
|
|
282
|
+
|
|
283
|
+
By default the status description is `<type>: <message>` and the event
|
|
284
|
+
carries `exception.type` and `exception.message` (cut to 1 KB, cleaned as
|
|
285
|
+
described in [Privacy](#privacy): secrets, local paths, user and host name
|
|
286
|
+
removed). With `hide_inputs` or `hide_outputs` both carry the exception type
|
|
287
|
+
only. No stack trace is recorded.
|
|
288
|
+
|
|
289
|
+
Cancelling the task that runs the agent (`asyncio.CancelledError`) or
|
|
290
|
+
leaving `stream()` before it ends (`GeneratorExit`) ends the open spans
|
|
291
|
+
with status ERROR, description `cancelled` and `mcp_use.cancelled` =
|
|
292
|
+
`true`, without an exception event. A span whose own end never came
|
|
293
|
+
because its parent ended first is ended with `mcp_use.incomplete` =
|
|
294
|
+
`true` and status ERROR, `ended without a result`.
|
|
295
|
+
|
|
296
|
+
If the callback itself fails (starting a span, reading a payload, setting
|
|
297
|
+
an attribute), it logs at debug level and the agent goes on unchanged.
|
|
298
|
+
Inside `fi_instrumentation.suppress_tracing()` it records nothing.
|
|
299
|
+
|
|
300
|
+
## Turning it off
|
|
301
|
+
|
|
302
|
+
Leave the callback out. `callbacks=[]` is the Python switch for no
|
|
303
|
+
callbacks at all: mcp-use's `ObservabilityManager` returns that empty list
|
|
304
|
+
as is and does not add its default Langfuse handler
|
|
305
|
+
(`mcp_use/agents/observability/callbacks_manager.py:72-74`). With
|
|
306
|
+
`callbacks=None`, mcp-use uses its Langfuse handler when Langfuse is
|
|
307
|
+
configured. There is no `observe=False` on the Python `MCPAgent` (that is
|
|
308
|
+
the TypeScript agent).
|
|
309
|
+
|
|
310
|
+
## Other tracing in the same process
|
|
311
|
+
|
|
312
|
+
- **traceAI-mcp (`traceai_mcp`)** works at the MCP transport. Version
|
|
313
|
+
0.1.2 records no spans of its own; it carries trace context in the
|
|
314
|
+
`_meta` of MCP requests. With both packages installed you get the same
|
|
315
|
+
spans as with this one alone: one agent span and one tool span per tool
|
|
316
|
+
call, none duplicated (tested). Because this package's spans are not made
|
|
317
|
+
current, the context `traceai_mcp` sends is whichever span is current in
|
|
318
|
+
your code. mcp-use binds `stdio_client` when it is imported
|
|
319
|
+
(`mcp_use/client/task_managers/stdio.py:12`), so run
|
|
320
|
+
`MCPInstrumentor().instrument()` before importing `mcp_use` for
|
|
321
|
+
`traceai_mcp`'s stdio wrapper to apply.
|
|
322
|
+
- **traceAI-langchain** adds its own tracer to every LangChain callback
|
|
323
|
+
manager, so an `MCPAgent` run would also produce a full LangChain tree
|
|
324
|
+
(graph, nodes, model and tool runs). Use one of the two for an agent.
|
|
325
|
+
- **mcp-use's own observability**: the Langfuse handler is used only when
|
|
326
|
+
`callbacks` is `None` (see above). Laminar is set up when `mcp_use` is
|
|
327
|
+
imported if `LAMINAR_PROJECT_API_KEY` is set and `lmnr` is installed,
|
|
328
|
+
whatever `callbacks` holds (`mcp_use/agents/observability/__init__.py:6`,
|
|
329
|
+
`laminar.py:19-37`); `MCP_USE_LAMINAR=false` turns it off.
|
|
330
|
+
- **mcp-use's usage telemetry** sends anonymized product events to PostHog
|
|
331
|
+
and Scarf, not spans; this package does not change it.
|
|
332
|
+
`MCP_USE_ANONYMIZED_TELEMETRY=false` turns it off
|
|
333
|
+
(`mcp_use/telemetry/telemetry.py:139`).
|
|
334
|
+
|
|
335
|
+
## Limits
|
|
336
|
+
|
|
337
|
+
- Recorded text is cut on a UTF-8 character boundary after it is cleaned
|
|
338
|
+
(secrets, then hidden inputs/outputs, then PII): 4 KB for each content
|
|
339
|
+
attribute, 256 bytes for names and ids (model, provider, tool name,
|
|
340
|
+
tool-call id, exception type) and 1 KB for the error message in the
|
|
341
|
+
status and the `exception` event. With `pii_redaction`, `FITracer` runs its own PII pass on every
|
|
342
|
+
attribute after the cut; a token such as `<PHONE_NUMBER>` can make an
|
|
343
|
+
attribute a few bytes longer than its cap. The status and events are not
|
|
344
|
+
passed through it. At most 32 messages and 16 tool calls per message are
|
|
345
|
+
recorded per LLM span, and 128 chunk events per streamed LLM span.
|
|
346
|
+
- One callback tracks at most 10,000 open runs. Past that, the oldest
|
|
347
|
+
agent run is ended with `mcp_use.incomplete` and forgotten. Ending a run
|
|
348
|
+
looks only at the open runs of its own agent run, not at other agents'.
|
|
349
|
+
- With `use_server_manager=True`, mcp-use restarts the graph run when the
|
|
350
|
+
tool set changes during a run, up to 3 times
|
|
351
|
+
(`mcp_use/agents/mcpagent.py:741-876`); each restart is a new agent span.
|
|
352
|
+
The server manager's own tools return their failures as mcp-use errors
|
|
353
|
+
without a `tool` key (`mcp_use/agents/managers/tools/connect_server.py:73`,
|
|
354
|
+
`disconnect_server.py:39`, `list_servers_tool.py:47`), so those tool spans
|
|
355
|
+
end OK with the error as their result. This path is not covered by the
|
|
356
|
+
tests.
|
|
357
|
+
- With `output_schema`, mcp-use formats the answer after the graph run with
|
|
358
|
+
a model call that gets no callbacks (`mcp_use/agents/mcpagent.py:595`),
|
|
359
|
+
so that call has no span.
|
|
360
|
+
- A remote agent (`MCPAgent(agent_id=...)`) never reads `callbacks`
|
|
361
|
+
(`mcp_use/agents/mcpagent.py:117-120`) and is not traced.
|
|
362
|
+
- The Python `MCPAgent` has no `flush()`. The provider `register()`
|
|
363
|
+
returns exports what is left when the process exits; in a long-running
|
|
364
|
+
process call `trace_provider.force_flush()` when you need the spans now.
|
|
365
|
+
- The callback runs on the agent's event loop, not in a thread. With
|
|
366
|
+
`register(batch=False)`, each span is exported synchronously on that loop
|
|
367
|
+
as it ends.
|
|
368
|
+
- Passed to a LangChain runnable other than `MCPAgent`, the callback still
|
|
369
|
+
names the outermost run `mcp_use.agent`.
|
|
370
|
+
- Tested with mcp-use 1.7.1 only (the latest release on 2026-10-16).
|
|
371
|
+
|
|
372
|
+
## Tests
|
|
373
|
+
|
|
374
|
+
From the repository root:
|
|
375
|
+
|
|
376
|
+
```bash
|
|
377
|
+
env -u PYTHONPATH PYTHONPATH="python/frameworks/mcp-use:python:python/tests" \
|
|
378
|
+
uv run --no-project --python 3.11 \
|
|
379
|
+
--with pytest --with pytest-asyncio --with opentelemetry-api --with opentelemetry-sdk \
|
|
380
|
+
--with opentelemetry-instrumentation --with opentelemetry-exporter-otlp-proto-http \
|
|
381
|
+
--with wrapt --with requests --with jsonschema --with protobuf --with opentelemetry-proto \
|
|
382
|
+
--with 'mcp-use==1.7.1' \
|
|
383
|
+
pytest python/frameworks/mcp-use/tests -q -p no:cacheprovider --noconftest -o addopts= -rfEs
|
|
384
|
+
```
|
|
385
|
+
|
|
386
|
+
Nothing calls a real model, MCP server or Future AGI. The LLM is a
|
|
387
|
+
scripted LangChain chat model. The MCP server is the FastMCP server in
|
|
388
|
+
`tests/_mcp_server.py`, on a 127.0.0.1 port for most tests and over stdio
|
|
389
|
+
for the contract test; the example test uses the example's own stdio
|
|
390
|
+
calculator server. Those send spans through
|
|
391
|
+
`fi_instrumentation.register()` to the shared `harness.Receiver` on
|
|
392
|
+
127.0.0.1 and check the `/tracer/v1/traces` path, both auth headers,
|
|
393
|
+
`project_type=observe`, that content is exported by default and not with
|
|
394
|
+
`FI_HIDE_INPUTS`/`FI_HIDE_OUTPUTS`, and that no key, stack trace or local
|
|
395
|
+
path is exported either way.
|
|
396
|
+
The example test runs `examples/agent_with_tools.py` as its own process,
|
|
397
|
+
once alone and once with `traceai_mcp` instrumented. The suite turns off
|
|
398
|
+
mcp-use's usage telemetry.
|
|
399
|
+
|