curl --request POST \
--url https://api.opal.dev/v1/agent-activity/mcp-config \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"servers": [
{
"name": "<string>",
"scope": "<string>",
"transport": "<string>",
"url": "<string>",
"command_hash": "<string>"
}
],
"reporter": {
"configured_email": "<string>",
"claude_account_email": "<string>",
"git_email": "<string>",
"os_user": "<string>"
}
}
'import requests
url = "https://api.opal.dev/v1/agent-activity/mcp-config"
payload = {
"servers": [
{
"name": "<string>",
"scope": "<string>",
"transport": "<string>",
"url": "<string>",
"command_hash": "<string>"
}
],
"reporter": {
"configured_email": "<string>",
"claude_account_email": "<string>",
"git_email": "<string>",
"os_user": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
servers: [
{
name: '<string>',
scope: '<string>',
transport: '<string>',
url: '<string>',
command_hash: '<string>'
}
],
reporter: {
configured_email: '<string>',
claude_account_email: '<string>',
git_email: '<string>',
os_user: '<string>'
}
})
};
fetch('https://api.opal.dev/v1/agent-activity/mcp-config', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.opal.dev/v1/agent-activity/mcp-config",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'servers' => [
[
'name' => '<string>',
'scope' => '<string>',
'transport' => '<string>',
'url' => '<string>',
'command_hash' => '<string>'
]
],
'reporter' => [
'configured_email' => '<string>',
'claude_account_email' => '<string>',
'git_email' => '<string>',
'os_user' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.opal.dev/v1/agent-activity/mcp-config"
payload := strings.NewReader("{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.opal.dev/v1/agent-activity/mcp-config")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.opal.dev/v1/agent-activity/mcp-config")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"received": 123,
"recorded": 123
}Report MCP server configuration
Prototype. Reports the MCP servers configured in Claude Code on one developer’s machine, as the Opal hook kit read them: user-level and per-project servers in ~/.claude.json, a project’s .mcp.json, managed-mcp.json, and servers a plugin provides when they can be found.
For each server the kit sends its name, the scope it was configured in, its transport, and either its URL (http, sse) or a hash of its command’s shape (stdio). It never sends environment values, headers or command arguments, which can hold secrets. Opal adds each server to the organization’s MCP server registry and records that this person has it configured. Nothing on the machine is changed.
Like /agent-activity, this is telemetry from cooperating machines: the identity and the list are what the machine says. The bearer token establishes the organization and nothing finer.
curl --request POST \
--url https://api.opal.dev/v1/agent-activity/mcp-config \
--header 'Authorization: Bearer <token>' \
--header 'Content-Type: application/json' \
--data '
{
"servers": [
{
"name": "<string>",
"scope": "<string>",
"transport": "<string>",
"url": "<string>",
"command_hash": "<string>"
}
],
"reporter": {
"configured_email": "<string>",
"claude_account_email": "<string>",
"git_email": "<string>",
"os_user": "<string>"
}
}
'import requests
url = "https://api.opal.dev/v1/agent-activity/mcp-config"
payload = {
"servers": [
{
"name": "<string>",
"scope": "<string>",
"transport": "<string>",
"url": "<string>",
"command_hash": "<string>"
}
],
"reporter": {
"configured_email": "<string>",
"claude_account_email": "<string>",
"git_email": "<string>",
"os_user": "<string>"
}
}
headers = {
"Authorization": "Bearer <token>",
"Content-Type": "application/json"
}
response = requests.post(url, json=payload, headers=headers)
print(response.text)const options = {
method: 'POST',
headers: {Authorization: 'Bearer <token>', 'Content-Type': 'application/json'},
body: JSON.stringify({
servers: [
{
name: '<string>',
scope: '<string>',
transport: '<string>',
url: '<string>',
command_hash: '<string>'
}
],
reporter: {
configured_email: '<string>',
claude_account_email: '<string>',
git_email: '<string>',
os_user: '<string>'
}
})
};
fetch('https://api.opal.dev/v1/agent-activity/mcp-config', options)
.then(res => res.json())
.then(res => console.log(res))
.catch(err => console.error(err));<?php
$curl = curl_init();
curl_setopt_array($curl, [
CURLOPT_URL => "https://api.opal.dev/v1/agent-activity/mcp-config",
CURLOPT_RETURNTRANSFER => true,
CURLOPT_ENCODING => "",
CURLOPT_MAXREDIRS => 10,
CURLOPT_TIMEOUT => 30,
CURLOPT_HTTP_VERSION => CURL_HTTP_VERSION_1_1,
CURLOPT_CUSTOMREQUEST => "POST",
CURLOPT_POSTFIELDS => json_encode([
'servers' => [
[
'name' => '<string>',
'scope' => '<string>',
'transport' => '<string>',
'url' => '<string>',
'command_hash' => '<string>'
]
],
'reporter' => [
'configured_email' => '<string>',
'claude_account_email' => '<string>',
'git_email' => '<string>',
'os_user' => '<string>'
]
]),
CURLOPT_HTTPHEADER => [
"Authorization: Bearer <token>",
"Content-Type: application/json"
],
]);
$response = curl_exec($curl);
$err = curl_error($curl);
curl_close($curl);
if ($err) {
echo "cURL Error #:" . $err;
} else {
echo $response;
}package main
import (
"fmt"
"strings"
"net/http"
"io"
)
func main() {
url := "https://api.opal.dev/v1/agent-activity/mcp-config"
payload := strings.NewReader("{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}")
req, _ := http.NewRequest("POST", url, payload)
req.Header.Add("Authorization", "Bearer <token>")
req.Header.Add("Content-Type", "application/json")
res, _ := http.DefaultClient.Do(req)
defer res.Body.Close()
body, _ := io.ReadAll(res.Body)
fmt.Println(string(body))
}HttpResponse<String> response = Unirest.post("https://api.opal.dev/v1/agent-activity/mcp-config")
.header("Authorization", "Bearer <token>")
.header("Content-Type", "application/json")
.body("{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}")
.asString();require 'uri'
require 'net/http'
url = URI("https://api.opal.dev/v1/agent-activity/mcp-config")
http = Net::HTTP.new(url.host, url.port)
http.use_ssl = true
request = Net::HTTP::Post.new(url)
request["Authorization"] = 'Bearer <token>'
request["Content-Type"] = 'application/json'
request.body = "{\n \"servers\": [\n {\n \"name\": \"<string>\",\n \"scope\": \"<string>\",\n \"transport\": \"<string>\",\n \"url\": \"<string>\",\n \"command_hash\": \"<string>\"\n }\n ],\n \"reporter\": {\n \"configured_email\": \"<string>\",\n \"claude_account_email\": \"<string>\",\n \"git_email\": \"<string>\",\n \"os_user\": \"<string>\"\n }\n}"
response = http.request(request)
puts response.read_body{
"received": 123,
"recorded": 123
}Authorizations
Bearer authentication header of the form Bearer <token>, where <token> is your auth token.
Headers
The identity the reporting client claims - an email, or an operating-system user name. Unverified, used the same way as on /agent-activity.
Body
Response
How many servers were read and recorded.
Was this page helpful?