Skip to content

Add ytptube MCP server - #1

Merged
Snuffy2 merged 21 commits into
mainfrom
feature/ytptube-mcp
Aug 2, 2026
Merged

Snuffy2 merged 21 commits into
mainfrom
feature/ytptube-mcp

Conversation

@Snuffy2

@Snuffy2 Snuffy2 commented Aug 2, 2026

Copy link
Copy Markdown
Owner

Summary

Adds a local stdio MCP server for self-hosted ytptube instances, with an explicit read-only default so clients can inspect and manage downloads safely.

What Changed

  • Added 27 MCP tools for ytptube health, URL inspection, queue/history, archives, metadata, tasks, presets, logs, and yt-dlp options.
  • Added local/remote base-URL configuration with Basic authentication and an apikey fallback; all returned credentials and header/query secrets are redacted.
  • Added YTPTUBE_ALLOW_MUTATIONS=false as the default guard for every state-changing operation; metadata generation and history file deletion require explicit opt-in.
  • Added setup documentation, Codex stdio configuration guidance, and a Vitest suite covering authentication, redaction, upstream task contracts, mutation gating, retry, and metadata paths.

Why

ytptube exposes a capable self-hosted HTTP API, but MCP clients need a narrow, credential-safe interface with predictable controls over destructive or state-changing actions.

Summary by CodeRabbit

  • New Features

    • Added a local stdio MCP server for interacting with YTPTube.
    • Added tools for connectivity, downloads, queues, history, archives, metadata, tasks, and presets.
    • Added HTTP(S) configuration with Basic or API-key authentication.
    • Added read-only defaults with optional mutation controls.
    • Added validation, timeout handling, structured errors, and sensitive-data redaction.
  • Documentation

    • Added setup, configuration, usage, security, and recovery guidance.
  • Tests

    • Added comprehensive coverage for configuration, authentication, server tools, validation, errors, and redaction.

Greptile Summary

Adds a local stdio MCP server that exposes ytptube operations through validated tools, with mutations disabled by default.

  • Implements configuration, authentication, request handling, timeout behavior, and credential redaction.
  • Registers tools covering health, downloads, history, archives, metadata, tasks, presets, logs, and yt-dlp options.
  • Adds setup and security documentation plus a comprehensive Vitest suite.

Confidence Score: 5/5

The PR appears safe to merge, with no blocking failure remaining.

No blocking failure remains; the previously reported plaintext credential transport behavior is retained as an optional warning or documentation consideration for self-hosted deployments.

Important Files Changed

Filename Overview
src/config.ts Parses the ytptube base URL, optional paired credentials, authentication mode, timeout, and mutation opt-in.
src/client.ts Implements authenticated ytptube HTTP requests, timeout handling, response parsing, and structured upstream errors.
src/server.ts Defines and registers the MCP tool schemas and handlers, including mutation gating and input validation.
src/redact.ts Redacts configured credentials and sensitive header or query values from returned data and errors.
src/index.ts Loads checkout-relative environment configuration and starts the MCP server over stdio.
tests/server.test.ts Exercises tool contracts, mutation controls, validation, metadata operations, and upstream request behavior.

Reviews (4): Last reviewed commit: "fix review feedback safeguards" | Re-trigger Greptile

@coderabbitai

coderabbitai Bot commented Aug 2, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds a self-hosted ytptube MCP server with environment configuration, authenticated HTTP access, secret redaction, read-only and mutation tools, stdio startup, documentation, and automated tests.

Changes

ytptube MCP server

Layer / File(s) Summary
Project setup and operating constraints
package.json, tsconfig.json, .env.example, .gitignore, AGENTS.md, README.md
Defines package scripts, compiler settings, environment variables, ignored files, development constraints, and operating documentation.
Environment configuration
src/config.ts, tests/config.test.ts
Validates URLs, credentials, authentication mode, timeout values, and mutation settings.
HTTP transport and secret redaction
src/client.ts, src/redact.ts, tests/client.test.ts, tests/redact.test.ts
Adds authenticated requests, timeout handling, structured API errors, response parsing, and recursive redaction of sensitive values.
MCP tool registration and stdio startup
src/server.ts, src/index.ts
Registers ytptube connectivity, download, history, task, and preset tools with validation, mutation gating, endpoint routing, dotenv loading, and stdio startup.
Behavior validation
tests/index.test.ts, tests/server.test.ts
Tests dotenv precedence, mutation blocking, payload mapping, endpoint selection, input validation, numeric identifiers, annotations, and secret redaction in results and errors.

Estimated code review effort: 4 (Complex) | ~60 minutes

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 0.00% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly and concisely describes the main change: adding a ytptube MCP server.

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

Comment thread src/config.ts
Keep request abort protection active through response body consumption, redact serialized authentication fields, and align numeric ID schemas with task and preset handlers.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@package.json`:
- Around line 2-5: Add the package manifest’s private flag alongside the
existing metadata so npm treats this project as non-publishable and rejects
accidental npm publish attempts. Preserve the current name, version,
description, and module type settings.

In `@README.md`:
- Around line 50-58: Add two README examples under “Mutation safety”: one
invoking a documented read-only tool that continues to work with mutations
disabled, and one invoking a documented state-changing tool that the mutation
gate rejects before any network request. Keep both examples consistent with the
public tool contract and existing `YTPTUBE_ALLOW_MUTATIONS` behavior.
- Around line 9-10: Update the Markdown table separator immediately after the
header row so it contains three separator cells matching the Tool group, Tools,
and What it is for columns; leave the header and table content unchanged.

In `@src/redact.ts`:
- Around line 13-27: The redact function in src/redact.ts#L13-L27 must remove
each object from seen after its subtree finishes processing: wrap the object
traversal in try/finally and call seen.delete(value) in finally, preserving
active-ancestor cycle detection. In tests/redact.test.ts#L5-L59, add separate
regression tests for duplicate nested references under different keys (both
preserved) and a genuine self-reference (mapped to "[CIRCULAR]").

In `@src/server.ts`:
- Line 158: Update the input schemas for ytptube_generate_task_metadata,
ytptube_patch_task, ytptube_update_task, ytptube_patch_preset, and
ytptube_update_preset to declare id: numericId directly. Remove the redundant
numericId.parse(id) calls in each handler and pass the validated numeric id
through unchanged; leave the already-correct get-task and get-preset definitions
unchanged.
- Around line 168-172: Update the descriptions for ytptube_create_tasks and
ytptube_update_task to document the actual payload contract enforced by
taskCreatePayload.parse and taskCreate.parse: identify required fields such as
name and url, and state that unsupported extra fields including cookies and
config are rejected. Keep the intentionally loose arbitraryObject schemas and
existing mutation-gate behavior unchanged.

In `@tests/client.test.ts`:
- Around line 88-99: The client test suite needs coverage for the
AbortError-to-TIMEOUT mapping. Add a test alongside the existing transport
failure test that uses a fetch mock which remains pending until its AbortSignal
is triggered, advances fake timers to invoke the request timeout, and asserts
the rejected YtptubeApiError has code "TIMEOUT".

In `@tests/redact.test.ts`:
- Around line 5-59: Add a regression test in the redact suite covering both
reference cases: pass one shared nested object under two different keys and
assert both results retain the fully redacted object without "[CIRCULAR]", then
pass a self-referencing object and assert the recursive reference becomes
"[CIRCULAR]". Use the existing redact function and assertion style.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 9a84fd75-927d-4f20-91b0-a1d033ae85ea

📥 Commits

Reviewing files that changed from the base of the PR and between debbf90 and 2921eb1.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (15)
  • .env.example
  • .gitignore
  • AGENTS.md
  • README.md
  • package.json
  • src/client.ts
  • src/config.ts
  • src/index.ts
  • src/redact.ts
  • src/server.ts
  • tests/client.test.ts
  • tests/config.test.ts
  • tests/redact.test.ts
  • tests/server.test.ts
  • tsconfig.json

Comment thread package.json
Comment thread README.md Outdated
Comment thread README.md
Comment thread src/redact.ts
Comment thread src/server.ts Outdated
Comment thread src/server.ts Outdated
Comment thread tests/client.test.ts
Comment thread tests/redact.test.ts
Snuffy2 added 10 commits August 1, 2026 21:34
Cover escaped serialized headers, authorization schemes, and equals-delimited cookie diagnostics before MCP output serialization.
Limit ytptube URL inputs to HTTP(S), load checkout-local .env configuration, and redact common credential assignments in returned text.
Redact URL userinfo and refresh tokens in returned text, and mark cancellation and overwrite-capable tools as potentially destructive.
Reject raw yt-dlp CLI strings for write operations and strengthen escape-aware credential redaction for returned logs and errors.
Keep read-only URL inspection within its documented API boundary by rejecting forwarded raw yt-dlp argument strings.
Expose strict nested write schemas to MCP clients and remove every plaintext authorization header value from returned output.
Remove Authorization and Proxy-Authorization values even when they appear within a returned diagnostic line.
Protect cookie payload values when backend logs or errors serialize the public cookies field.
Align extras with the documented API contract, normalize numeric bulk history IDs, and redact common credential aliases in returned output.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 5

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@src/redact.ts`:
- Around line 41-44: Update redactSerializedHeaders to redact unterminated
values through the end of output instead of continuing when end exceeds
output.length, while preserving delimiter handling for terminated values. In the
replacement construction, simplify the two tail slices after the redacted marker
to a single output.slice(end) call, and adjust startPattern.lastIndex
consistently with the resulting output.
- Around line 5-7: The quoted-value portions of SERIALIZED_SECRET and
ESCAPED_SERIALIZED_SECRET can backtrack excessively on unterminated,
backslash-rich input. Replace their value-matching expressions with mutually
exclusive quote-safe alternatives that explicitly handle non-quote/non-backslash
characters and escapes, avoiding [\s\S], while preserving matching of properly
terminated serialized secrets used by redactString().

In `@src/server.ts`:
- Around line 174-176: Update the registration of ytptube_set_history_archive so
its destructive flag is enabled, matching ytptube_queue_control and
ytptube_generate_history_nfo. Preserve the existing archived-dependent
POST/DELETE behavior and all other registration arguments.
- Around line 121-123: Update the ytptube_inspect_url registration to pass the
z.object schema directly to register, removing the unsafe as unknown as
ZodRawShape assertion while preserving the existing schema and handler.

In `@tests/index.test.ts`:
- Around line 11-19: Update the test setup around mkdtemp in the
environment-loading test to wrap file creation and assertions in a try/finally
block, and remove the temporary directory in finally using rm(directory, {
recursive: true, force: true }).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: ASSERTIVE

Plan: Pro Plus

Run ID: 429bf193-9c9b-4a56-b92b-b8a7af177ab9

📥 Commits

Reviewing files that changed from the base of the PR and between 2921eb1 and b54948d.

⛔ Files ignored due to path filters (1)
  • package-lock.json is excluded by !**/package-lock.json
📒 Files selected for processing (10)
  • README.md
  • package.json
  • src/client.ts
  • src/index.ts
  • src/redact.ts
  • src/server.ts
  • tests/client.test.ts
  • tests/index.test.ts
  • tests/redact.test.ts
  • tests/server.test.ts

Comment thread src/redact.ts Outdated
Comment thread src/redact.ts Outdated
Comment thread src/server.ts
Comment on lines +121 to +123
register("ytptube_inspect_url", "Inspect URL metadata without adding it to the download queue.", z.object({
url: httpUrl, preset: z.string().optional(), force: z.boolean().optional(), entries: z.boolean().optional(),
}).strict() as unknown as ZodRawShape, (input) => call("/api/yt-dlp/url/info", { query: input as RequestOptions["query"] }));

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

📐 Maintainability & Code Quality | 🔵 Trivial | 💤 Low value

🧩 Analysis chain

🌐 Web query:

Does @modelcontextprotocol/sdk 1.17.3 registerTool accept a ZodObject for inputSchema or only a ZodRawShape?

💡 Result:

The registerTool method in @modelcontextprotocol/sdk accepts both ZodObject and ZodRawShape for the inputSchema parameter [1][2][3]. In the current SDK, ZodObject is the standard, preferred way to define schemas [4][5]. While the SDK also supports ZodRawShape (a plain object record like { field: z.string }) as a backward-compatible shorthand for v1 compatibility, it does so by internally auto-wrapping the raw shape with z.object [1][2][6]. You are encouraged to use z.object({...}) directly, as the raw-shape shorthand is deprecated and intended to be removed in future major versions [2][4][3].

Citations:


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== locate src/server.ts and package versions =="
git ls-files | rg '(^|/)src/server\.ts$|package\.json|package-lock\.json|pnpm-lock\.yaml|yarn\.lock' || true

if [ -f src/server.ts ]; then
  echo
  echo "== sr/src/server.ts outline =="
  ast-grep outline src/server.ts --view expanded || true
  echo
  echo "== relevant src/server.ts lines =="
  nl -ba src/server.ts | sed -n '1,180p'
fi

echo
echo "== package manager / version declarations =="
for f in package.json package-lock.json pnpm-lock.yaml yarn.lock; do
  [ -f "$f" ] || continue
  echo "--- $f ---"
  if [ "$f" = "package.json" ]; then
    jq '.dependencies["`@modelcontextprotocol/sdk`"], .devDependencies["`@modelcontextprotocol/sdk`"]' "$f" || true
  else
    rg -n '"`@modelcontextprotocol/sdk`"|`@modelcontextprotocol/sdk`|version' "$f" | head -80
  fi
done

echo
echo "== tool registrations in repository =="
rg -n 'register\(".*", ".*"|z\.object\(\{[\s\S]{0,250}\}\)\.strict|registerTool|inputSchema' src package.json 2>/dev/null || true

echo
echo "== inspect installed typings if present =="
if [ -d node_modules/@modelcontextprotocol/sdk ]; then
  rg -n 'registerTool|inputSchema|ZodRawShape|ZodObject' node_modules/@modelcontextprotocol/sdk -g '*.ts' -g '*.d.ts' | head -120
  fd -e dts -e ts . node_modules/@modelcontextprotocol/sdk -d 5 -i | head -80
else
  echo "node_modules/@modelcontextprotocol/sdk not present"
fi

Repository: Snuffy2/ytptube-mcp

Length of output: 1318


🏁 Script executed:

#!/bin/bash
set -euo pipefail

echo "== src/server.ts relevant lines =="
awk 'NR<=180 { printf "%6d\t%s\n", NR, $0 }' src/server.ts

echo
echo "== package version declarations =="
jq -r '.dependencies["`@modelcontextprotocol/sdk`"], .devDependencies["`@modelcontextprotocol/sdk`"]' package.json 2>/dev/null || true

echo
echo "== tool registrations =="
rg -n 'register\(".*",".*"|httpUrl|strict\(\)|registerTool|inputSchema' src/server.ts src package.json || true

echo
echo "== installed MCP SDK typings/source snippets =="
if [ -d node_modules/@modelcontextprotocol/sdk ]; then
  rg -n 'registerTool|inputSchema|ZodRawShape|ZodObject' node_modules/@modelcontextprotocol/sdk -g '*.ts' -g '*.d.ts' | head -120
else
  echo "node_modules/@modelcontextprotocol/sdk not present"
fi

echo
echo "== package-lock `@modelcontextprotocol/sdk` snippet =="
python3 - <<'PY'
import json
with open('package-lock.json') as f:
    data=json.load(f)
for path in ['node_modules/@modelcontextprotocol/sdk']:
    if 'packages' in data and path in data['packages']:
        print(data['packages'][path].get('version'))
PY

Repository: Snuffy2/ytptube-mcp

Length of output: 12855


Align the MCP input schema with the SDK contract.

registerTool accepts z.object(...), so ytptube_inspect_url does not need as unknown as ZodRawShape. Keep the wrapper; remove the unsafe type assertion.

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@src/server.ts` around lines 121 - 123, Update the ytptube_inspect_url
registration to pass the z.object schema directly to register, removing the
unsafe as unknown as ZodRawShape assertion while preserving the existing schema
and handler.

Comment thread src/server.ts Outdated
Comment thread tests/index.test.ts Outdated
@Snuffy2
Snuffy2 merged commit 54c65a6 into main Aug 2, 2026
2 checks passed
@Snuffy2
Snuffy2 deleted the feature/ytptube-mcp branch August 2, 2026 03:14
@Snuffy2 Snuffy2 added the feature label Aug 2, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant