Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 23 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,28 @@
# Changelog

## 0.10.16: /mcp/apps names no plan, and monitors.alerts

`/mcp/apps` is the surface app stores list, so its results name no plan, price, offer or upgrade link.

- A refusal there says what happened in a plan-free sentence.
- A search filter the account can't use gets "The before filter isn't available here. Search again without it."
- Dates past the account's newest get "Results here cover videos published up to 2026-10-11. Set after to 2026-10-11 or earlier."
- Used-up credits get "This account is out of Arcmira credits for now."
- A video with no caption lines gets "This video has no caption track Arcmira can read, so there are no lines to return."
- A transcript Arcmira is still preparing gets "Arcmira is still preparing this transcript. Read it again in a minute." Any other transcript that isn't ready gets "Arcmira can't return this here."
- Other refusals keep only their sentences that name no plan, price, offer or link.
- A refusal's code names no plan there: `filter_requires_paid` reads `filter_unavailable`, `freshness_requires_paid` reads `outside_date_range`, and any other code that names a plan reads `not_available`.
- Asking for a credential there names no sign-up offer or link: "No credential was sent. Sign in through the host, or send Authorization: Bearer with an account key." A refused key gets "The key sent has been revoked." or "The key sent is not a live account key."
- A video YouTube has no record of gets the API's own sentence, "YouTube has no video with this id. It may have been removed or the link may be mistyped.", with no caption note, on both paths.
- A search whose results stop before today says which dates it covers: "These results cover videos published from 2026-08-12 to 2026-10-11."
- Results there carry no `unlock`, `freshness`, `access`, gate or doc link. Answers keep only the fields the tools know: a search's `window` keeps `after` and `before`, its `search_index` keeps `state` and `missing_before`, and feedback keeps `feedback_id`.
- A result's `watch_url` there is a YouTube or Arcmira watch link, or is left out. A refusal's other fields drop any value that names a plan, a price or another link. The feedback tool's description there leaves out "Costs nothing."
- A tool name `/mcp` retired is an unknown tool on `/mcp/apps`, which never served it.
- `/mcp` keeps the API's words, codes, unlocks and field order unchanged.
- A test sends every refusal and note through each `/mcp/apps` route and fails on a plan name, also inside a snake_case code, on a gate field, or on a link other than a YouTube watch link. The transcript kind `arcmira_premium` passes only as a `source` filter value or a result's `source`.

The program client gains `arcmira.monitors.alerts(monitorId, { limit? })`, a read of `GET /v1/monitors/{id}/alerts`: the alerts a monitor sent, newest first, each with the `video_id` that `transcript(video)` reads. An agent with the MCP server can now act on a monitor's alerts without an API key.

## 0.10.15: six weekly-job prompts on /mcp

`/mcp` now serves six MCP prompts: `weekly-brand-watch`, `weekly-competitor-reads`, `weekly-person-tracker`, `weekly-sponsor-scout`, `weekly-show-digest` and `weekly-monitor-roundup`. Picking one runs the job once now. Then it gives back the job with the names filled in, and the steps to run it every week as a scheduled task.
Expand Down
2 changes: 1 addition & 1 deletion gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"mcpServers": {
"arcmira": {
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@arcmira/mcp",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"keywords": [
"mcp",
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/.claude-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"author": {
"name": "Arcmira",
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/.codex-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"author": {
"name": "Arcmira",
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/.cursor-plugin/plugin.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"author": {
"name": "Arcmira",
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/gemini-extension.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"mcpServers": {
"arcmira": {
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/plugin.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"$schema": "https://agent-plugins.org/schemas/1.0.0/plugin.schema.json",
"name": "arcmira",
"version": "0.10.15",
"version": "0.10.16",
"description": "YouTube transcript search and monitoring for your AI: exact quotes, full transcripts and speakers.",
"author": {
"name": "Arcmira",
Expand Down
2 changes: 1 addition & 1 deletion plugins/arcmira/skills/arcmira/references/monitors.md
Original file line number Diff line number Diff line change
@@ -1,3 +1,3 @@
# Monitors

MONITORS. A monitor sends alerts for the entities it follows, by email to the account address or by Slack, realtime, hourly or daily. arcmira.monitors.list() lists the user's monitors and monitors.trackers(id) what one follows. Changes run only in arcmira_execute_write; nothing is deleted, and update(id, { paused: true }) pauses. Confirm the monitor and its delivery with the user before a write. create needs name and notify_frequency. Slack needs notify_slack: true and a workspace from arcmira.integrations.slack(): its id as slack_integration_id and default_channel_id as slack_channel_id; with none, the user connects one at https://arcmira.com/dashboard/integrations. addEntities takes up to 90 ids in one call. addName follows an exact name that resolve does not find (a show by its UC id). Topic spellings ("data centers", "datacenters") can be separate ids; follow each. A name may already be followed: list() and trackers(id) show what is, so check them before creating a monitor. A result with attached: false names its reason: entity_not_found, entity_type_not_trackable, tracker_limit_reached, or tracked_in_another_monitor (current_monitor_id names it; attachTrackers moves it once the user agrees). Creating a monitor uses no credits; each alert uses 25 credits from the account's plan, then its on-demand budget.
MONITORS. A monitor sends alerts for the entities it follows, by email to the account address or by Slack, realtime, hourly or daily. arcmira.monitors.list() lists the user's monitors, monitors.trackers(id) what one follows and monitors.alerts(id) the alerts it sent, each with the video_id to read. Changes run only in arcmira_execute_write; nothing is deleted, and update(id, { paused: true }) pauses. Confirm the monitor and its delivery with the user before a write. create needs name and notify_frequency. Slack needs notify_slack: true and a workspace from arcmira.integrations.slack(): its id as slack_integration_id and default_channel_id as slack_channel_id; with none, the user connects one at https://arcmira.com/dashboard/integrations. addEntities takes up to 90 ids in one call. addName follows an exact name that resolve does not find (a show by its UC id). Topic spellings ("data centers", "datacenters") can be separate ids; follow each. A name may already be followed: list() and trackers(id) show what is, so check them before creating a monitor. A result with attached: false names its reason: entity_not_found, entity_type_not_trackable, tracker_limit_reached, or tracked_in_another_monitor (current_monitor_id names it; attachTrackers moves it once the user agrees). Creating a monitor uses no credits; each alert uses 25 credits from the account's plan, then its on-demand budget.
2 changes: 1 addition & 1 deletion plugins/arcmira/skills/company-watch/references/monitor.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Follow and save to a monitor

MONITORS. A monitor sends alerts for the entities it follows, by email to the account address or by Slack, realtime, hourly or daily. arcmira.monitors.list() lists the user's monitors and monitors.trackers(id) what one follows. Changes run only in arcmira_execute_write; nothing is deleted, and update(id, { paused: true }) pauses. Confirm the monitor and its delivery with the user before a write. create needs name and notify_frequency. Slack needs notify_slack: true and a workspace from arcmira.integrations.slack(): its id as slack_integration_id and default_channel_id as slack_channel_id; with none, the user connects one at https://arcmira.com/dashboard/integrations. addEntities takes up to 90 ids in one call. addName follows an exact name that resolve does not find (a show by its UC id). Topic spellings ("data centers", "datacenters") can be separate ids; follow each. A name may already be followed: list() and trackers(id) show what is, so check them before creating a monitor. A result with attached: false names its reason: entity_not_found, entity_type_not_trackable, tracker_limit_reached, or tracked_in_another_monitor (current_monitor_id names it; attachTrackers moves it once the user agrees). Creating a monitor uses no credits; each alert uses 25 credits from the account's plan, then its on-demand budget.
MONITORS. A monitor sends alerts for the entities it follows, by email to the account address or by Slack, realtime, hourly or daily. arcmira.monitors.list() lists the user's monitors, monitors.trackers(id) what one follows and monitors.alerts(id) the alerts it sent, each with the video_id to read. Changes run only in arcmira_execute_write; nothing is deleted, and update(id, { paused: true }) pauses. Confirm the monitor and its delivery with the user before a write. create needs name and notify_frequency. Slack needs notify_slack: true and a workspace from arcmira.integrations.slack(): its id as slack_integration_id and default_channel_id as slack_channel_id; with none, the user connects one at https://arcmira.com/dashboard/integrations. addEntities takes up to 90 ids in one call. addName follows an exact name that resolve does not find (a show by its UC id). Topic spellings ("data centers", "datacenters") can be separate ids; follow each. A name may already be followed: list() and trackers(id) show what is, so check them before creating a monitor. A result with attached: false names its reason: entity_not_found, entity_type_not_trackable, tracker_limit_reached, or tracked_in_another_monitor (current_monitor_id names it; attachTrackers moves it once the user agrees). Creating a monitor uses no credits; each alert uses 25 credits from the account's plan, then its on-demand budget.

Pass each block as one program to the tool its title names, with the names swapped for the user's.

Expand Down
2 changes: 1 addition & 1 deletion server.json
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@
"url": "https://github.com/arcmira/mcp",
"source": "github"
},
"version": "0.10.15",
"version": "0.10.16",
"websiteUrl": "https://arcmira.com",
"remotes": [
{
Expand Down
3 changes: 2 additions & 1 deletion src/auth.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import { DEFAULT_API_BASE, SRC, USER_AGENT, noKeyError, type CredentialFailure, type Env } from './api.ts';
import { MCP_PATH } from './server.ts';
import { APPS_SURFACE, PROGRAM_SURFACE } from './surface.ts';

/**
* The MCP authorization spec on top of the key rungs. A request with no bearer, or with a
Expand Down Expand Up @@ -47,7 +48,7 @@ export function isOAuthBearer(key: string | null): key is string {

/** The 401 that starts the OAuth dance. The body names the sign-up, for a host that cannot run it. */
export function challenge(origin: string, reason: CredentialFailure = 'no_credential', path: string = MCP_PATH): Response {
const error = noKeyError(reason);
const error = (path === MCP_PATH ? PROGRAM_SURFACE : APPS_SURFACE).error(noKeyError(reason));
return Response.json(
{
jsonrpc: '2.0',
Expand Down
3 changes: 2 additions & 1 deletion src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -196,7 +196,8 @@ export default {
);
}
if (failure !== null) return challenge(url.origin, failure, surface.path);
const retired = await retiredCall(request);
// The retired names were /mcp tools; /mcp/apps never served them.
const retired = surface.path === MCP_PATH ? await retiredCall(request) : null;
if (retired !== null) return retired;
const api = createApiClient(env, key);
const client = request.headers.get(CLIENT_HEADER);
Expand Down
Loading
Loading