claude-tools
Provides tools for interacting with Google's Gemini AI, including asking questions, reviewing diffs, and analyzing files.
Click on "Install Server".
Wait a few minutes for the server to deploy. Once ready, it will show a "Started" state.
In the chat, type
@followed by the MCP server name and your instructions, e.g., "@claude-toolsAsk Gemini for a second opinion on my approach to refactoring the database layer."
That's it! The server will respond to your query, and you can continue using it as needed.
Here is a step-by-step guide with screenshots.
claude-tools
Local MCP servers that give Claude Code access to other tools mid-session.
gemini-bridge
Exposes three tools backed by the Gemini CLI:
ask_gemini(prompt, context="")— ask Gemini a question, e.g. for a second opinion on an approach.review_diff(repo_path, instructions="")— runsgit diffinrepo_pathand sends it to Gemini for critique. Pass the absolute path of the repo you want reviewed; the bridge runs as its own background process and does not share Claude Code's working directory.ask_gemini_about_files(file_paths, question)— reads one or more full files and asks Gemini a question about them. Use this instead ofask_gemini'scontextparam when the files are too large for Claude's own context, or when you want Gemini's take on whole files/modules rather than a truncated excerpt — Gemini's window is large enough to hold much more (up to 500k chars) thanask_gemini/review_diffallow (60k chars). Pass absolute paths; the bridge runs as its own process and does not share Claude Code's cwd.
Every call is logged to log.jsonl (gitignored) as an audit trail of what
was asked and answered.
Setup
Install the Gemini CLI:
npm install -g @google/gemini-cliAuthenticate with an API key — as of gemini-cli 0.50.0, the free
oauth-personallogin tier ("Gemini Code Assist for individuals") is no longer accepted; Google points individual users at a separate product (Antigravity) instead. Use an API key:Get a free key from Google AI Studio.
Put it in
~/.gemini/.env:GEMINI_API_KEY=your-key-hereSet
~/.gemini/settings.jsonto use it:{ "security": { "auth": { "selectedType": "gemini-api-key" } } }
Install this project's dependencies:
cd ~/git/claude-tools python3 -m venv .venv .venv/bin/pip install -r requirements.txtRegister the server with Claude Code (user scope, so it's available in every project):
claude mcp add gemini-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/gemini_bridge.pyRestart Claude Code / reload the window.
ask_gemini,review_diff, andask_gemini_about_filesshould show up as callable tools.
Notes
gemini_bridge.pyreads~/.gemini/.envitself and setsGEMINI_CLI_TRUST_WORKSPACE=trueon every call, rather than relying on gemini-cli's own env-file auto-discovery (unreliable when invoked as a subprocess from an arbitrary cwd) or its interactive trusted-folder prompt (which headless calls can't answer).Gemini CLI's
-p/--promptnon-interactive flag is flagged upstream as a candidate for future deprecation (gemini-cli#16025). If it's renamed, only_call_gemini()ingemini_bridge.pyneeds updating.Context and diffs are truncated to 60k characters before being sent to Gemini to avoid blowing past its context window.
ask_gemini_about_filesuses a much higher 500k-character ceiling, since its whole point is to use Gemini's larger window on full files.Before invoking the Gemini CLI,
_call_gemini()does a quick 5s TCP preflight check against Gemini's API host. On a flaky connection (e.g. a phone hotspot), this fails fast with a clear error instead of blocking for the fullGEMINI_TIMEOUT(120s). Restart Claude Code / reload the window after pulling this change, since the running server process won't pick it up otherwise.
Related MCP server: mcp-local-llm
ollama-bridge
Exposes two tools backed by a locally running Ollama instance:
prefilter_diff(repo_path, model="qwen2.5-coder:7b")— runsgit diffinrepo_pathand sends it to a local Ollama model for a cheap first-pass triage before spending areview_diff(Gemini) call on it. The response starts withCLEAN:orFLAGGED:— only escalate toreview_diffwhen it'sFLAGGED, or when this tool errors (e.g. Ollama isn't running); never skip review outright just because the local pass errored.triage_log(repo_path, log_path, model="qwen2.5-coder:7b")— reads a build/test log already written to disk (redirect a failing command's output first, e.g.cmd > out.log 2>&1) and sends it to a local Ollama model to pull out just the root failure (FILE:/ERROR:/CONTEXT:), instead of reading the whole raw log directly. ReturnsNO FAILURE FOUND.for a clean run.log_pathmust resolve insiderepo_path(absolute or relative, same containment rule asrepo-bridge'sget_file) — rejected otherwise.
Every call is logged to ollama_log.jsonl (gitignored) as an audit trail.
Setup
Install Ollama and pull a coding-capable model:
ollama pull qwen2.5-coder:7bThis tool has no new dependency beyond what's already in
requirements.txt— it talks to Ollama's local REST API with the standard library'surllib, consistent with the rest of this repo's bridges.Register the server with Claude Code (user scope):
claude mcp add ollama-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/ollama_bridge.pyRestart Claude Code / reload the window.
prefilter_diffshould show up as a callable tool.
Notes
This exists to save Gemini API calls on routine commits, not to replace
review_diff. A quantized 7B local model catches the obvious stuff (dead code, naming, syntax slips) but reliably misses subtler bugs and security issues a frontier model catches — treat aCLEANverdict as "nothing obvious jumped out," not "safe to skip a real review," for anything consequential.Reuses
review_diff's own diff-selection order (vs HEAD, then staged--cached, then plain unstaged) so both tools always look at the same diff._call_ollamasets an explicitnum_ctx: 8192on every request. Ollama defaults to 2048 regardless of the model's real context length, which would silently left-truncate any diff nearMAX_CONTEXT_CHARSand dropPREFILTER_INSTRUCTIONSentirely — caught byreview_diffon this tool's own first commit before it ever shipped.temperature: 0.0is set alongside it for a more consistent CLEAN/FLAGGED verdict.Verified end-to-end against this repo's own pending
README.mddiff on 2026-07-24:prefilter_diffpicked up the real diff and returned aCLEANverdict fromqwen2.5-coder:7brunning locally — call and response both landed inollama_log.jsonlas expected.qwen2.5-coder:7bwas picked as the default because it's the only locally installed model (of qwen2.5-coder, dolphin-mistral, llama3, deepseek-coder, plus several custom personas) that reports tool-use/code capability rather than plain chat completion — override viamodelfor a different local model.triage_logreads an existing log file rather than executing a command itself — deliberately, to keep this bridge's subprocess surface limited togit diff(a fixed, safe command) rather than adding an arbitrary-command-execution tool. Redirect a failing command's output to a file first (cmd > out.log 2>&1), then triage that.triage_logtruncates from the start of the log via_truncate_keep_tail, the opposite ofprefilter_diff's_truncate— a build/test failure is almost always near the end of a log (the start is setup noise: dependency resolution, banners), unlike a diff where head-truncation is fine. Uses a largernum_ctx: 24576(LOG_NUM_CTX) thanprefilter_diff's8192sinceMAX_LOG_CHARS(40k chars) needs more headroom than a same-ratio scale-up would give —review_diffflagged that 40k chars could run denser than ~2 chars/token on symbol-heavy logs, soLOG_NUM_CTXwas set with margin rather than scaled proportionally toprefilter_diff's ratio.triage_logrequiresrepo_pathand resolveslog_pathinside it via the same_resolve_in_repocontainment checkrepo-bridgeuses forget_file— added afterreview_diffflagged the first draft (a barelog_pathwith no scoping) as an arbitrary-file-read risk: an unscoped path could be pointed at~/.ssh,.envfiles, etc._call_ollama'sURLErrorhandler checksisinstance(e.reason, TimeoutError)before the genericOSErrorcheck —review_diffcaught that a real (slow-but-reachable-Ollama) timeout is itself anOSErrorsubclass, so without checkingTimeoutErrorfirst it was misreported as "not reachable - isollama serverunning?" instead of a timeout.triage_logalways appends a pointer back to the fulllog_pathand line/char count alongside the model's summary — a 7B model can misidentify the root cause in a complex multi-error log, so the raw log stays oneReadaway rather than being fully replaced by the summary.Verified against a synthetic pytest log (42 tests, 1 real failure buried in passing-test noise): correctly extracted the failing file/line, exact
AssertionError, and relevant traceback lines, ignoring the noise. A second synthetic clean-run log correctly returnedNO FAILURE FOUND.
tn3270-bridge
Exposes five tools backed by py3270 (which
drives s3270 under the hood) for automating TN3270 mainframe green-screen
sessions:
connect(host, port=23)— opens a session, returns asession_id.send_keys(session_id, keys)— typeskeysinto the current field. A"\n"inkeyspresses Enter (e.g."myuser\n"typesmyuserand submits it). Returns the resulting screen.read_screen(session_id, structured=False)— returns the current screen as plain text. Withstructured=True, returns JSON instead:{"cursor": {"row", "col"}, "fields": [{"row", "col", "protected", "hidden", "autoskip", "modified", "text"}, ...]}— use this when an agent needs to know where to type (which field is unprotected, which one is a hidden password field) rather than just what's on screen. Row/col are 1-indexed and refer to the field's attribute-byte position, so the first typeable character is one column to the right ofcol.send_function_key(session_id, key)— sendsPFn/PAn/Clear/Enter. Returns the resulting screen.disconnect(session_id)— closes the session.
Sessions live in memory for the lifetime of the server process (one per
Claude Code session) — disconnect any session you're done with rather than
letting it leak. Every call is logged to tn3270_log.jsonl (gitignored).
Setup
Install
s3270(part of the x3270 suite):brew install x3270Install this project's dependencies (shared
.venvwith gemini-bridge):cd ~/git/claude-tools .venv/bin/pip install -r requirements.txtRegister the server with Claude Code:
claude mcp add tn3270-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/tn3270_bridge.pyRestart Claude Code / reload the window.
Notes
Plain-text
read_screenuses x3270'sAscii()script command. Structured mode usesReadBuffer(Ascii), which annotates the buffer withSF(...)markers at each field's attribute byte; the byte's bits are decoded per the 3270 field-attribute spec (IBM GA23-0059) intoprotected/hidden/autoskip/modified.hiddenis what marks password fields — verified against a live TSO logon screen, wherePassword/New Password/MFA Tokenall came backhidden: trueandUseriddid not.Field
row/coland cursorrow/colcome from two different x3270 commands with different indexing (ReadBufferis 1-indexed,Query (Cursor)is 0-indexed) —_structured_screen()normalizes both to 1-indexed. Confirmed by checking the cursor lands one column past an unprotected field's attribute byte, which is where typing actually starts.All five tools have been exercised against a live TN3270 host (a local test mainframe on
localhost:3270):connect+read_screenpulled back the logon banner,send_keys("TSO\n")advanced from the logon-type prompt to the TSO/E LOGON screen,send_function_key("PF3")logged off back to the banner, and structuredread_screencorrectly identified the one unprotected field on the banner screen and the hidden password fields on the TSO/E LOGON screen.
repo-bridge
Exposes four tools for getting codebase context from a repo outside Claude Code's own working directory:
search_codebase(repo_path, query, max_results=50, ignore_case=False)— grepsrepo_pathforquery(a regex). Usesgit grepwhenrepo_pathis a git repo (respects.gitignore), otherwise plaingrep -r. Returnspath:line:contentper match.get_file(repo_path, path)— returns the full contents ofpath(relative torepo_path), truncated past 60k chars. Rejects paths that escaperepo_path(e.g.../../etc/passwd).list_structure(repo_path, max_entries=500)— returns a directory tree as indented text. Usesgit ls-files(tracked files only) whenrepo_pathis a git repo, otherwise walks the filesystem skipping common junk dirs (node_modules,.venv,__pycache__, etc.).get_symbol(repo_path, name, language="", max_results=10)— finds function/class/method/type definitions namednameand returns their source text via tree-sitter. Supportspython,javascript,typescript,tsx,go,rust,java,ruby,c, andcpp. Greps for files that referencenamefirst rather than parsing the whole repo, and returns every match found (up tomax_results), not just the first.
Pass the absolute path of the repo you want as repo_path for every tool —
this server runs as its own process and does not share Claude Code's
working directory.
Setup
Install this project's dependencies (shared
.venv):cd ~/git/claude-tools .venv/bin/pip install -r requirements.txtRegister the server with Claude Code:
claude mcp add repo-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/repo_bridge.pyRestart Claude Code / reload the window.
Notes
Uses the official per-language
tree-sitter-*packages (prebuilt wheels, compiled at install time), not thetree-sitter-language-packpackage — that one downloads grammars over the network on first use, which is a bad fit for this repo's other lesson-learned (see gemini-bridge's network preflight check above) and just failed outright when tried on a flaky connection.get_symbolmatches by each grammar'snamefield on definition-like node types (function_definition,class_declaration, etc.) — this works generically across languages without per-language field lookups._find_definitions()walks the whole tree (including inside already-matched nodes, so e.g. two same-named methods in two different classes in one file both surface) and results are capped atmax_results, defaulting to 10.C and C++
function_definitionnodes are the one exception to the genericname-field lookup above: their identifier is nested inside adeclaratorchain (apointer_declaratorfor pointer return types, etc.) ending in afunction_declaratorwhose owndeclaratorfield is the actual identifier._c_family_function_name()inrepo_bridge.pyunwraps that chain; struct/enum/union/class specifiers in C/C++ do expose anamefield directly and don't need it.Verified against this repo (Python) and small standalone fixtures for TypeScript, Go, Rust, Java, Ruby, C, and C++ —
get_symbolcorrectly pulled a function/struct (or class/method) from each, with correct line ranges.
linkedin-bridge
Exposes three tools for managing LinkedIn posts on behalf of the authenticated member, all via LinkedIn's Posts API:
post_to_linkedin(text, visibility="PUBLIC")— publishes a text post.visibilityis"PUBLIC"or"CONNECTIONS". Returns the live post URL on success.update_linkedin_post(post_url_or_urn, text)— replaces the text of an existing post. Takes either the live URL or a bare URN. Only needs thew_member_socialscope this app already has.delete_linkedin_post(post_url_or_urn)— permanently deletes a post. Irreversible.
All three publish, edit, or delete under the user's real identity — always confirm the exact action/text before calling any of them, never call them unprompted.
Every call is logged to linkedin_log.jsonl (gitignored) as an audit trail.
Setup
Create a LinkedIn Company Page, then a developer app at linkedin.com/developers/apps associated with it, with the Share on LinkedIn product added (grants the
w_member_socialscope). The app needs a real privacy policy URL — this repo's own consulting site's privacy page is an example of a minimal one.Add an Authorized redirect URL of
http://localhost:8765/callbackon the app's Auth tab, and note the Client ID and Client Secret.Put the credentials in
~/.linkedin/.env(create the file yourself in a text editor — don't paste secrets through an agent if avoidable):LINKEDIN_CLIENT_ID=... LINKEDIN_CLIENT_SECRET=...then
chmod 600 ~/.linkedin/.env.Run the one-time OAuth flow:
.venv/bin/python linkedin_oauth_setup.pyThis opens a browser for LinkedIn's consent screen, exchanges the resulting code for an access token, fetches the member's person URN, and writes both back into
~/.linkedin/.env.Register the server with Claude Code:
claude mcp add linkedin-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/linkedin_bridge.py
Notes
Standard LinkedIn apps don't get a refresh token without extra approval — access tokens last ~60 days. Re-run
linkedin_oauth_setup.pyonce one expires;post_to_linkedinwill surface LinkedIn's own error message if a call is attempted with an expired token.Uses
urllibfrom the standard library rather than adding an HTTP client dependency, consistent with the rest of this repo's bridges.Solved: the earlier "posts sometimes render truncated" issue was LinkedIn's "little" text format. The
commentaryfield isn't plain text — it's a small markup language for mentions/hashtags, and characters reserved for that markup (( ) [ ] { } @ # < > \ * _ ~) must be backslash-escaped to appear as literal text. Every post logged during the original investigation was checked against this: every single one containing an unescaped(or)rendered truncated in the feed, every one without either character rendered in full — 11/11 with no exceptions._escape_little_format()now escapes all reserved characters automatically before everypost_to_linkedin/update_linkedin_postcall, except#wordsequences (left alone so intentional hashtags still render as hashtags). Confirmed fixed with a live test post containing parentheses.update_linkedin_post/delete_linkedin_postdon't needr_member_social(LinkedIn's read-back permission, currently closed for new access requests) - only reading a post back to verify its content needs that, so there's still no way to check a post's live content without a human looking at it.Verified end-to-end: OAuth flow completed, a real post published successfully via
post_to_linkedin, then updated viaupdate_linkedin_post(tested with the full URL form) and deleted viadelete_linkedin_post(tested with the bare URN form) - both input styles work.
youtube-bridge
Exposes five tools for a solo-creator video pipeline: transcribe a raw recording, mechanically tighten it, cut it down semantically, then upload it to YouTube on a schedule.
transcribe_video(video_path)— local faster-whisper transcription with timestamps. Writes<video_path>.transcript.jsonand returns[MM:SS - MM:SS] textlines for Claude to read and reason about what to cut.tighten_video(video_path, output_path="")— runs auto-editor for a mechanical first pass (cuts silence/dead air). Doesn't understand meaning — pair withcut_videofor semantic cuts (flubbed takes, restarts, rambling).cut_video(video_path, keep_segments, output_path="")— given a list of[start, end]second ranges to keep (picked by Claude from the transcript), re-encodes and concatenates via ffmpeg for frame-accurate cuts. Claude decides what to cut by reading the transcript; this tool only executes the mechanical trim.queue_video_for_upload(video_path, title, description, tags, category_id="28", publish_at="")— uploads asprivacyStatus: "private"withstatus.publishAtset, so YouTube itself flips the video public at that timestamp — no daemon or cron needed on this end. Ifpublish_atis omitted, computes the next open slot fromYOUTUBE_POST_TIMES(comma-separatedHH:MM, local time — one entry = 1/day, two = 2/day), reading/advancing state inyoutube_schedule_state.jsonso repeated calls in one batch-recording session spread out across days without double-booking. On success, moves the source file into aposted/subfolder (date-prefixed) so it drops out of the pending queue.list_pending_videos(folder="")— lists video files infolder(defaultYOUTUBE_VIDEO_DIR) not yet moved toposted/, i.e. what's left in a batch day's queue.
queue_video_for_upload schedules a video to go publicly live with no
further confirmation at publish_at — always confirm title/description/
tags/timing with the user before calling it, never call it unprompted, same
rule as linkedin-bridge.
Every call is logged to youtube_log.jsonl (gitignored).
Setup
Install
ffmpeg(brew install ffmpeg) and this project's Python dependencies (shared.venv,faster-whisperandauto-editorare inrequirements.txt):cd ~/git/claude-tools .venv/bin/pip install -r requirements.txtCreate a Google Cloud project, enable the YouTube Data API v3, and create an OAuth client of type Desktop app. Add
http://localhost:8766/callbackas an authorized redirect URI.Put the client credentials in
~/.youtube/.env:YOUTUBE_CLIENT_ID=... YOUTUBE_CLIENT_SECRET=... YOUTUBE_VIDEO_DIR=/path/to/your/raw-recordings-folder YOUTUBE_POST_TIMES=10:00,17:00then
chmod 600 ~/.youtube/.env.Run the one-time OAuth flow (forces
access_type=offline&prompt=consentso Google actually returns a refresh token):.venv/bin/python youtube_oauth_setup.pyThis writes
YOUTUBE_REFRESH_TOKENback into~/.youtube/.envand prints the authorized channel name to confirm you authorized the right account.Register the server with Claude Code:
claude mcp add youtube-bridge --scope user -- \ ~/git/claude-tools/.venv/bin/python ~/git/claude-tools/youtube_bridge.pyRestart Claude Code / reload the window.
Notes
Unlike LinkedIn's ~60-day access token, Google's refresh token doesn't expire from normal use —
youtube_bridge.pyexchanges it for a fresh access token on every call rather than caching one, soyoutube_oauth_setup.pyshould only need to run once.publishAtrequiresprivacyStatus: "private"at upload time (YouTube rejects a scheduledpublic/unlistedupload) — the tool always sends"private", which is what triggers YouTube's own scheduling behavior.Uses
urllibfrom the standard library for OAuth and the resumable-upload protocol, consistent with the rest of this repo's bridges — nogoogle-api-python-clientdependency. The upload streams the video file from disk (a file object passed asdata, notread_bytes()) so large recordings don't get fully buffered into memory; it's still a single PUT rather than chunked with per-chunk retry, which would matter more for very large files or flaky connections.queue_video_for_uploadrejectspublish_atvalues less than 5 minutes out, andcut_videovalidateskeep_segments(sorted, non-overlapping,end > start) before touching ffmpeg — both fail fast with a clear error instead of wasting an upload/encode on bad input._run()catchesFileNotFoundErrorfor missing binaries (ffmpeg,ffprobe,auto-editor) and returns a clean "not found — is it installed and on PATH?" error through the normal returncode-check path, instead of crashing the tool call with a raw traceback.cut_videore-encodes at every cut (trim+concatfilter graph) rather than stream-copying, trading some encode time for frame-accurate boundaries — stream-copy cuts only land on keyframes, which would make Claude's semantic cut points imprecise.Default
category_idis"28"(Science & Technology) — override per call if a video fits better under"27"(Education) or"26"(Howto & Style).Scheduling logic (
_next_publish_slot) verified standalone: queuing 5 videos in a row againstYOUTUBE_POST_TIMES=10:00,17:00produced 2026-07-18 10:00, 2026-07-18 17:00, 2026-07-19 10:00, 2026-07-19 17:00, 2026-07-20 10:00 — correct 2/day spread with no double-booking.Full pipeline verified end-to-end 2026-07-18/19 (transcribe → tighten → queue → real OAuth upload), including three fixes found along the way:
tighten_videocalled bareauto-editorviasubprocess.run, which only exists in this project's.venv/bin, not on the MCP server's inheritedPATH.AUTO_EDITOR_BINnow resolves it explicitly (shutil.whichfirst, falling back to the venv's ownbin/next tosys.executable).macOS Screenshot/Screen Recording filenames insert a narrow no-break space (
U+202F) before AM/PM, visually identical to a normal space but byte-different — any retyped (vs. copy-pasted) path silently failedPath.exists()._resolve_video_path()now falls back to a whitespace-normalized filename match within the same directory across all four file-taking tools.The first real upload flickered and had audio skips. Two compounding causes, both in
tighten_video's defaultauto-editorinvocation: (1) macOS screen recordings are variable-frame-rate, and left to its default auto-editor timed the output off the source's average fps, landing on an arbitrary non-standard rate (52.41fps); (2) auto-editor's default bitrate (~1.4Mbps observed) was far too low for a high-res (3024x1898) screen recording with sharp text, producing visible compression-artifact flicker. Fixing the frame rate alone did not resolve it — the low bitrate was the dominant cause.tighten_videonow passes--frame-rate 60(TIGHTEN_OUTPUT_FPS) and--video-bitrate 10M(TIGHTEN_VIDEO_BITRATE, comfortably above the source's own ~4Mbps). Caught only after publishing — a private/scheduled upload with a bad encode isn't somethingyoutube-bridgecan fix or delete itself (no update/delete tool exists yet, unlikelinkedin-bridge); both bad uploads had to be deleted by hand in YouTube Studio before their scheduled publish time.
tighten_videodisabled 2026-07-19, the fps/bitrate fix above did not actually resolve the flicker. Two more videos processed through the fixedtighten_videostill showed the artifact and were unusable. Isolated the cause with an A/B test: the same recording, uploaded completely raw and unedited with no auto-editor pass at all, had no flicker. So the artifact comes from auto-editor's re-encode step itself, not the source capture and not YouTube's transcode, but the exact cause within auto-editor isn't identified yet.tighten_videonow returns an explanatory error instead of running, rather than silently producing unusable output.transcribe_video,cut_video, andqueue_video_for_uploadare unaffected. Roadmapped below to revisit once the real cause is found.Deliberately excluded from
mcpo_config.json, same rationale aslinkedin-bridge(see mcpo Notes below) — publishing tools stay MCP-only so the "confirm before calling" rule can't be bypassed by an HTTP client holding the proxy's API key.
mcpo proxy
Fronts gemini-bridge, tn3270-bridge, and repo-bridge with
mcpo, so tool-calling harnesses that
don't speak MCP natively (e.g. Ollama or llama.cpp-based agents) can call
these tools over plain HTTP/OpenAPI instead. linkedin-bridge and
youtube-bridge are deliberately excluded - see Notes.
Setup
Install this project's dependencies (shared
.venv,mcpois inrequirements.txt):cd ~/git/claude-tools .venv/bin/pip install -r requirements.txtRun it, pointing at
mcpo_config.jsonand picking a real API key (not the placeholder below):.venv/bin/mcpo --port 8000 --api-key "your-own-key-here" --config mcpo_config.jsonEach server's tools are now live at
http://localhost:8000/<server-name>/<tool-name>(e.g.http://localhost:8000/repo-bridge/list_structure), with interactive OpenAPI docs per-server athttp://localhost:8000/<server-name>/docsand a combined spec athttp://localhost:8000/openapi.json. Every actual tool call requiresAuthorization: Bearer <api-key>; the docs/spec endpoints themselves are intentionally public (mcpo's default behavior).
Notes
linkedin-bridgeis excluded frommcpo_config.jsonon purpose.post_to_linkedin's "always confirm the exact text with the user first" rule is something Claude Code follows as an instruction, not something the proxy enforces - any HTTP client holding the--api-keycould otherwise trigger a real, public LinkedIn post with no confirmation step. Keeping it MCP-only means posting only ever happens through Claude Code's own guarded tool-call flow.Verified end-to-end: started mcpo with all three servers, confirmed a real
list_structurecall succeeds with the API key and returns 401 without it, and confirmed the (intentionally public)openapi.json//docsendpoints are reachable either way.
Roadmap
Add a third gemini-bridge tool for querying Gemini's larger context window on full files, not just diffs.
repo-bridge: expand
get_symbollanguage support beyond python/javascript/typescript/tsx/go — added rust, java, ruby, c, and cpp.repo-bridge:
get_symbolshould return all matches instead of just the first.tn3270-bridge: structured
read_screenmode (field positions, protected/unprotected, cursor location) alongside the plain-text dump, for when an agent needs to know where to type, not just what's shown.Front the MCP servers with an
mcpo(MCP-to-OpenAPI) proxy so tool-calling harnesses built on Ollama or llama.cpp — which don't speak MCP natively — can call these tools over plain HTTP.linkedin-bridgeexcluded on purpose (see mcpo Notes).linkedin-bridge: dig further into the post-truncation issue — root caused to LinkedIn's "little" text format (see Notes above); fixed by auto-escaping reserved characters before every post/update.
linkedin-bridge: add
update_linkedin_post/delete_linkedin_post— both work with thew_member_socialscope this app already has.Add
youtube-bridge: transcribe/tighten/cut a raw recording, then queue it for scheduled upload (YouTube's ownpublishAt, no daemon) with source files auto-moved toposted/. Upload/OAuth path verified end-to-end with a real upload (see Notes above).youtube-bridge: add
update_youtube_video/delete_youtube_video(mirroringlinkedin-bridge's pattern). Surfaced 2026-07-19 when a bad first upload (flicker/audio-skip from the fps bug, see Notes) sat privately scheduled on YouTube with no way to remove or replace it via MCP — had to be fixed by hand in YouTube Studio.youtube-bridge: find the actual cause of
tighten_video's flicker/ scanline artifact and re-enable it. Confirmed 2026-07-19 the fps/ bitrate fix didn't fix it, and that the artifact is specific to auto-editor's re-encode (raw unedited upload of the same recording had no artifact), but not yet which part of auto-editor's pipeline is at fault. Currently disabled, returns an error instead of running.linkedin-bridge: scheduled posting. LinkedIn's API has no server-side scheduled publish for personal profiles (that's a Company Page / Campaign Manager feature), so this would need Claude-side scheduling (a cron routine calling
post_to_linkedinat a set time) with pre-approved text, mirroringyoutube-bridge'spublishAtpattern but without native platform support. Surfaced 2026-07-21.youtube-bridge: chunked resumable upload with retry, for large files or flaky connections (current version sends the whole video in one PUT).
youtube-bridge: thumbnail upload (
thumbnails.set) once the core transcribe → cut → schedule path is verified end-to-end.linkedin-bridge: add read-back support (a tool that fetches a post's live content) once
r_member_socialis available. Blocked on LinkedIn, no ETA — that permission is currently closed to all new access requests, not just under heavy review, so there's nothing to do here until that changes.Add
ollama-bridge: aprefilter_difftool backed by a local Ollama model (qwen2.5-coder:7b), so routine diffs get a free/offline triage pass before spending areview_diff(Gemini) call — only escalate when it comes backFLAGGED. Verified end-to-end 2026-07-24.ollama-bridge: add
triage_log, a second tool that extracts just the root failure (FILE:/ERROR:/CONTEXT:) from a build/test log file via the same local model, instead of reading the whole raw log. Verified end-to-end 2026-07-24 against synthetic pytest logs (one failing, one clean).
This server cannot be installed
Maintenance
Resources
Unclaimed servers have limited discoverability.
Looking for Admin?
If you are the server author, to access and configure the admin panel.
Related MCP Servers
- AlicenseAqualityBmaintenanceLocal MCP server that wraps the headless Claude Code CLI as MCP tools, providing stateless access to Claude's coding capabilities through prompt-based interactions. It enables users to execute Claude Code commands with various prompt formats and structured outputs directly from MCP clients.Last updated3MIT
- Alicense-qualityCmaintenanceMCP server that lets Claude Code delegate mechanical tasks to a local LLM for summarization, classification, extraction, and drafting.Last updated159MIT
- Flicense-qualityCmaintenanceA local MCP server that lets Claude Code start, resume, and wait for Codex app-server sessions while humans inspect live sessions from a terminal.Last updated
- Alicense-qualityDmaintenanceA local MCP server that connects Claude Desktop to execute custom local code, such as generating custom greetings.Last updated6ISC
Related MCP Connectors
Hosted MCP server connecting claude.ai, ChatGPT and other AI apps to your own computer
Augments MCP Server - A comprehensive framework documentation provider for Claude Code
Hosted Amazon Seller and Vendor MCP server for Claude, ChatGPT, Cursor, Codex, Gemini, Copilot.
Latest Blog Posts
- Who's Calling? MCP Hosts Are an Identity Blind Spot (And the Spec Knows It)By Om-Shree-0709 on .mcpAgent IdentityOAuth 2.1
- Your AI Chatbot Just Exposed Your CEO's Salary to an InternBy Om-Shree-0709 on .Agent IdentityMCP SecurityOAuth Delegation
- Why MCP Servers Need Execution Sandboxing (And Why Your Current Stack Isn't Enough)By Om-Shree-0709 on .Agentic AiPrompt InjectionWebAssembly
MCP directory API
We provide all the information about MCP servers via our MCP API.
curl -X GET 'https://glama.ai/api/mcp/v1/servers/wren-creator/claude-tools'
If you have feedback or need assistance with the MCP directory API, please join our Discord server