Commit Graph
328 Commits
Author SHA1 Message Date
ab-ihsanoglu 15402b4423 Add a module for BTK database 2026-07-04 13:18:48 +03:00
saidsurucuandClaude Opus 4.8 1b483a6fcf fix(emsal): add per-IP rate limiting to prevent spurious empty results
UYAP Emsal (emsal.uyap.gov.tr) rate-limits per source IP, returning HTTP
429 (HTML error page, no Retry-After) after a small burst of rapid
requests. With no client-side throttling, sequential searches would fail
after the first few — making results appear term-dependent (always the
same later queries "returning 0") when the cause was purely request order
and rate. On the shared-egress-IP production deployment this was hit
constantly.

Add the same token-bucket + 429 back-pressure pattern already used by the
Bedesten client: requests are spaced ~3.5s apart and the bucket freezes on
an actual 429. Configurable via EMSAL_RATE_CAPACITY / EMSAL_RATE_REFILL_S /
EMSAL_RATE_MAX_WAIT_S.

Verified: seven sequential searches (incl. previously "failing" kıdem,
boşanma, kamulaştırma) all return results with no 429s.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-07-01 21:03:41 +03:00
saidsurucuandClaude Opus 4.8 cc055103fe docs: document AYM/Uyuşmazlık API rewrites in CLAUDE.md
Add a changelog entry for the new AYM JSON API and Uyuşmazlık ASP.NET
postback + PDF flow, and update a stale curl example to use
search_anayasa_unified.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 19:24:16 +03:00
saidsurucu 2c3347643d Merge: adapt AYM and Uyuşmazlık tools to rebuilt sites 2026-06-30 19:22:56 +03:00
saidsurucuandClaude Opus 4.8 fadc3b0bc0 fix(aym,uyusmazlik): adapt to rebuilt AYM and Uyuşmazlık sites
Both sites were rebuilt and their old endpoints now 404:
- AYM moved to a single-page app backed by a JSON API
  (POST /api/core/public/search, kararTipi NormDenetimi/BireyselBasvuru;
  full text via {id, size:1} -> "icerik" HTML). Old /Ara, /ND/, /BB/ gone.
- Uyuşmazlık moved to ASP.NET WebForms (viewstate postback to /, GridView
  results, decisions served as /Uploads/{EsasNo}.pdf). Old /Arama/Search gone.

Changes:
- New anayasa_mcp_module/api_client.py: shared KBB JSON client, base64url
  document-id codec, HTML->Markdown + HTML text stripping helpers.
- Rewrite anayasa client/bireysel_client/unified_client over the new API,
  preserving public method names and response models.
- Rewrite uyusmazlik client for the postback flow + GridView parse + PDF
  document conversion; simplify request model to text + scope + paging.
- Trim search_anayasa_unified and search_uyusmazlik_decisions tool signatures
  to parameters the new APIs actually support; drop dead enums.

Verified live via FastMCP client: search + document retrieval work for AYM
norm/bireysel and Uyuşmazlık.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 19:22:49 +03:00
saidsurucuandClaude Opus 4.8 6bbc656dc6 docs: add Claude Desktop local uv copy-paste install to README
Platforma göre claude_desktop_config.json yolunu otomatik tespit eden
kopyala-yapıştır komutu (macOS/Linux + Windows) ve manuel alternatif eklendi.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-18 19:01:44 +03:00
saidsurucuandClaude Opus 4.8 a062237474 docs: add local uv copy-paste install for Antigravity; bump to 0.2.1
README'ye Antigravity için lokal uvx kurulumunu otomatik yapan
kopyala-yapıştır komutu eklendi (~/.gemini/config/mcp_config.json).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
v0.2.1
2026-06-18 18:51:19 +03:00
Said Sürücü b69eda77af Merge pull request #28 from hburaktasyurek/tool-limit-alignment
Tool Routing: align descriptions with runtime behavior and reduce Bedesten request overhead
2026-06-16 11:53:09 +03:00
Hasan Burak Taşyürek 3927dcee8f feat(deep-research): reduce Bedesten request overhead
Use search-result metadata for Deep Research previews instead of fetching every candidate document.

This keeps the compatibility tools within upstream Bedesten rate limits and updates the README to match the current active tool set.
2026-06-13 00:07:03 +03:00
Said Sürücü 3768104679 Merge pull request #27 from Baijack-star/docs-remote-mcp-troubleshooting
Document remote MCP troubleshooting
2026-06-08 18:53:18 +03:00
saidsurucuandClaude Opus 4.7 aa580ffafc docs: update Pro version URL to yargi.betaspacestudio.com
Replace https://yargi-mcp-pro-production.up.railway.app with
https://yargi.betaspacestudio.com in:
- README.md Pro announcement at the top
- mcp_server_main.py rate-limit messages in search_bedesten_unified
  and get_bedesten_document_markdown (4 occurrences)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-06-02 18:02:50 +03:00
saidsurucuandClaude Opus 4.7 931eb3ca8f docs(readme): announce Yargı MCP Pro at the top
Add a top-of-README callout pointing to the professional version that
combines mevzuat and içtihat in a single MCP server:
https://yargi-mcp-pro-production.up.railway.app

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-31 16:53:39 +03:00
saidsurucuandClaude Opus 4.7 d258ad2375 Merge fix/anayasa-document-url-host: force correct host for AYM document URLs
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:06:24 +03:00
saidsurucuandClaude Opus 4.7 061887f870 fix(anayasa): force correct host for AYM document URLs by path
get_anayasa_document_unified 404'd when a /ND/ (Norm Denetimi) path was
supplied on the bireysel host (kararlarbilgibankasi) instead of the norm
host. Detection was netloc-first and passed the wrong-domain URL through
unchanged.

Add normalize_anayasa_document_url(): classify by path (/ND/ vs /BB/) and
re-key the host to the canonical domain, preserving query/fragment. Route
get_document_unified() off the normalized result. Verified end-to-end: the
previously-404 URL now returns the decision markdown.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-27 14:06:09 +03:00
saidsurucu ac611f840c Merge fix/kik-v2-dynamic-security-headers: KİK v2 dynamic request signing 2026-05-26 12:19:52 +03:00
saidsurucuandClaude Opus 4.7 c938f10ba2 fix(kik): generate v2 request-signing headers per-request
The KİK v2 API (ekapv2.kik.gov.tr) validates a timestamp embedded in the
X-Custom-Request-Ts header and rejects stale values with HTTP 401
"İstek zaman aşımına uğradı." The client previously sent hardcoded, captured
header values, so once that timestamp aged out every search 401'd across all
three decision types (uyusmazlik/duzenleyici/mahkeme).

Replicate the Angular HTTP interceptor: AES-192-CBC/PKCS7 encrypt a fresh uuid4
GUID and the current epoch-millis timestamp with the environment.r8fact key and
a random IV, regenerated on every request.

Verified live: all three decision types return results with hataKodu "0".

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-26 12:19:48 +03:00
Baijack-star 1356c4d020 Document remote MCP troubleshooting 2026-05-22 07:39:44 +08:00
saidsurucuandClaude Opus 4.7 5392435c7a docs(bedesten): point rate-limit message to Yargı MCP Pro beta
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-18 17:44:22 +03:00
saidsurucuandClaude Opus 4.7 96a5a538b2 perf(server): unblock event loop on rate-limit waits and markitdown
Two complementary changes to mitigate intermittent TLS handshake
timeouts and "notifications/cancelled: Bad Request" seen against the
single-worker uvicorn deployment.

1. bedesten rate-limiter back-pressure
   - Add optional ``max_wait`` to ``_TokenBucket.acquire``: if the next
     wait would exceed it, raise ``BedestenRateLimited`` immediately
     instead of sleeping. After a server-side 429 the bucket pauses for
     up to 30s; previously a queued request sat in ``asyncio.sleep``
     for that whole window, holding the worker slot and pushing the
     MCP client past its cancellation timeout.
   - ``search_bedesten_unified`` / ``get_bedesten_document_markdown``
     catch ``BedestenRateLimited`` and reuse the existing structured
     429-style response, so callers get a fast, clean retry signal.
   - Tunable via ``BEDESTEN_RATE_MAX_WAIT_S`` (default 8.0s).

2. Offload sync markitdown conversions to a thread
   - Every ``markitdown.convert*`` call site is now wrapped in
     ``asyncio.to_thread(...)`` across 14 modules (bedesten, yargitay,
     danistay, anayasa norm + bireysel, uyusmazlik, emsal, rekabet,
     gib, kvkk, sayistay, bddk, sigorta_tahkim, kik_v2). PDF / large
     HTML parsing was stalling the event loop for seconds, which on a
     single-worker deployment delayed every other in-flight request
     and queued new TLS handshakes until they timed out.

Verified locally:
- ``ast.parse`` + ``importlib.import_module`` on all 15 modified files
- ``mcp_server_main.create_app()`` constructs successfully
- New ``_TokenBucket.acquire(max_wait=...)`` smoke-tested across 6
  paths: capacity-available, no-arg backward compat, max_wait raise,
  max_wait wait+succeed, ``penalize_until`` + max_wait fast-raise.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-11 14:31:23 +03:00
saidsurucu 26aa3dacc6 fix(bedesten): include itemTypeList in fetch metadata search
The fetch tool's metadata lookup constructed BedestenSearchData without
the required itemTypeList field, causing a Pydantic validation error and
losing the chance to enrich the response with a proper title.
2026-05-08 21:58:30 +03:00
saidsurucuandClaude Opus 4.7 58457b076f feat(bedesten): client-side rate limiter with 429 back-pressure
Probed the live API (2026-05-08): the per-IP limit is 10 requests in a
rolling 30s window, with HTTP 429 + Retry-After: 30 on the 11th call.

Add a token bucket inside BedestenApiClient (default capacity=1, refill
1 token / 3.5s — strict serialization, no burst) so we stay below the
threshold by default. When the server still returns 429 (e.g. the egress
IP is shared with other clients), pause the whole bucket for the
Retry-After window so queued in-flight requests wait gracefully instead
of hammering. Tunable via BEDESTEN_RATE_CAPACITY / BEDESTEN_RATE_REFILL_S.

Verified: 14 concurrent requests after a clean cooldown -> 13 OK,
1 stray 429 (bucket auto-paused 22.5s, then drained cleanly).

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 21:10:37 +03:00
saidsurucuandClaude Opus 4.7 4521e1de85 fix(bedesten): suggest yargi-cli as fallback in 429 message
When the Bedesten API rate-limits us, point the model at the local
yargi-cli tool (https://github.com/saidsurucu/yargi-cli) so the user
has a working alternative while waiting out the limit.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:30:49 +03:00
saidsurucuandClaude Opus 4.7 8f04010c57 fix(bedesten): return structured 429 response instead of raising
Bedesten API can intermittently return HTTP 429 Too Many Requests.
Previously the tool raised, leaving the LLM with an unhandled error.
Now search_bedesten_unified returns a dict with error="rate_limit_exceeded"
and get_bedesten_document_markdown returns a BedestenDocumentMarkdown
whose markdown_content describes the rate limit, so the model can
inform the user and retry. Non-429 errors still propagate.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 20:18:12 +03:00
saidsurucuandClaude Opus 4.7 7ed9c25687 docs(readme): announce migration to yargimcp.surucu.dev
Add a prominent banner at the top of the README and inline notices
near the connection instructions stating the server has moved to
https://yargimcp.surucu.dev/mcp. The old https://yargimcp.fastmcp.app/mcp
endpoint is now a migration stub that returns only a notice tool.
Update Claude Desktop and Google Antigravity config URLs to the new host.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:43:32 +03:00
saidsurucuandClaude Opus 4.7 4fdc7a3689 fix(deploy): make migration_app entrypoint a FastMCP instance
The Dokploy FastMCP build pipeline runs `fastmcp inspect <module>:app`
and expects `app` to be a FastMCP instance, not a Starlette ASGI app.
Drop the `mcp.http_app()` wrapper and bind the FastMCP instance to
`app` directly so `fastmcp inspect` and `fastmcp run --transport http`
both work. Verified locally with `fastmcp inspect` and end-to-end MCP
initialize over `fastmcp run`.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:39:02 +03:00
saidsurucuandClaude Opus 4.7 1538a4c145 feat(deploy): add migration stub MCP app pointing to new URL
migration_app.py is a minimal FastMCP server with a single
migration_notice tool. Intended for the deprecated endpoint so
existing MCP clients learn the server has moved to
https://yargimcp.surucu.dev/mcp and instruct the user to update
their client configuration.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 00:29:32 +03:00
saidsurucuandClaude Opus 4.7 a24def2e66 feat(deploy): add minimal ASGI app and Dockerfile for simple deploys
Mirrors the mevzuat-mcp pattern: a thin app.py exposing
mcp.http_app() with a /health route, no FastAPI/CORS/OAuth wrapper.
Dockerfile builds on python:3.12-slim and runs uvicorn directly.
Removes Dockerfile/fly.toml entries from .dockerignore so the new
Dockerfile is included in the build context.

Existing asgi_app.py (api.yargimcp.com production) is untouched.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-07 13:13:22 +03:00
saidsurucuandClaude Opus 4.7 6b781b61d2 docs(semantic_search): recommend multilingual-e5-large for Turkish (#22)
Different embedding model families need different prompt prefixes —
Gemini wants "task: ... | query: ..." and "title: ... | text: ...",
e5 wants "query: ..." / "passage: ...", and using the wrong one
silently degrades retrieval quality. Add EMBEDDING_PROMPT_STYLE
(gemini/e5/raw) so the prefix matches the chosen model.

Defaults: gemini for OpenRouter (matches the existing default
google/gemini-embedding-001), e5 for the local provider (matches
the recommended multilingual-e5-large setup). Both override via
env var or constructor.

Update README and .env.example to recommend intfloat/multilingual-
e5-large served by HuggingFace Text Embeddings Inference (one
docker run) as the Turkish-optimized local setup, with a clear env
var reference table. Ollama and OpenRouter remain documented as
alternatives.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:55:42 +03:00
saidsurucuandClaude Opus 4.7 fb29146755 feat(semantic_search): support local OpenAI-compatible embedding servers (#22)
Adds a LocalEmbedder that targets any OpenAI-compatible embedding
endpoint (Ollama, llama.cpp, vLLM, LM Studio, ...). Zero new
Python dependencies — reuses the existing openai SDK with a
custom base_url. Defaults to Ollama at http://localhost:11434/v1
with nomic-embed-text @ 768 dims; override via env vars for other
servers/models (e.g. bge-m3 @ 1024 dims for better Turkish).

Refactors the shared encode/similarity logic into a private base
class so OpenRouterEmbedder and LocalEmbedder don't duplicate ~50
lines. OpenRouter keeps its ranking headers; local sends none.

Adds get_embedder() factory selecting the provider based on
EMBEDDING_PROVIDER (local) or OPENROUTER_API_KEY presence, and
is_semantic_search_available() that returns True for either path.
mcp_server_main now uses these so the semantic_search tool is
exposed when only a local server is configured.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:50:47 +03:00
saidsurucuandClaude Opus 4.7 42731a2c03 feat(semantic_search): make embedding model configurable (#22)
google/gemini-embedding-001 became paid on OpenRouter, leaving
users without credit unable to run the semantic_search tool. The
old code hardcoded the model and 3072 dimensions in three places.

Make OpenRouterEmbedder accept model/dimension via constructor
args or OPENROUTER_EMBEDDING_MODEL / OPENROUTER_EMBEDDING_DIMENSION
env vars, with the previous values as backward-compatible defaults.
Switch the VectorStore and the response payload in mcp_server_main
to read embedder.dimension instead of the hardcoded 3072 so a
configured non-Gemini model does not produce shape mismatches.

Bad dimension input (non-int or non-positive) now raises a clear
ValueError instead of a downstream shape error.

Documented the new env vars in .env.example.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:46:33 +03:00
saidsurucuandClaude Opus 4.7 ae5d590cca fix(sayistay): surface clear error when upstream WAF returns 418 (#23)
Verified 2026-05-03 against a real Chrome browser: POSTs to
/KararlarGenelKurul/DataTablesList consistently return HTTP 418
with the WAF block page "Bilgi Güvenliği Politikaları Gereği
Kısıtlanmıştır", regardless of headers, cookies, CSRF token, or
form payload. The block is server-side at sayistay.gov.tr and
cannot be worked around client-side. The Temyiz Kurulu and Daire
endpoints are unaffected (29k/22k records still return normally).

Detect the 418 + WAF marker in all three search methods and raise
a clear RuntimeError explaining it is an upstream restriction,
instead of the cryptic "Client error '418 I'm a teapot'" that
hides the real situation from MCP clients.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:41:35 +03:00
saidsurucuandClaude Opus 4.7 ee544dc603 fix(rekabet): return parsed decisions instead of empty array (#24)
Token-optimization commit e34d81b tightened RekabetDecisionSummary
fields from Optional[str]/Optional[HttpUrl] to plain str with ""
defaults, but client.py kept passing None for unparsed cells and
HttpUrl(...) for URLs. Pydantic v2 rejected both, the broad
except Exception swallowed every row, and decisions came back []
while total_records_found stayed populated.

Default unparsed string fields to "" and pass URL strings directly
to the model. Verified against the live API for empty args,
PdfText filter, and KararTuru filter.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-03 01:33:52 +03:00
saidsurucuandClaude Opus 4.7 355f505da9 docs: Update README for GİB özelge module
- Intro paragraph: add GİB Özelgeleri to institution list
- Feature bullets: add GİB Özelgeleri entry with supported filters
- Tool list: new "GİB Özelge Araçları" subsection covering
  search_gib_ozelge and get_gib_ozelge_document_markdown
- Counts: tool total 22 → 24, institution total 14 → 15

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 18:01:57 +03:00
saidsurucuandClaude Opus 4.7 4c06a5926b Add GİB özelge (tax rulings) MCP module
Introduces two tools backed by the gib.gov.tr public JSON API
(reverse-engineered from the Next.js SPA chunks):

- search_gib_ozelge: keyword, ozelgeNo, kanunNo, date-range, paging
  over 18k+ Revenue Administration tax rulings. Simple YYYY-MM-DD
  dates are auto-expanded to ISO 8601 to satisfy the backend.
- get_gib_ozelge_document_markdown: fetch a single ruling by numeric
  id and return 5000-char paginated Markdown with a metadata header
  block (title, ozelgeNo, tarih, kanun, kaynak).

Also prunes stale auth/Fly.io-era entries from uv.lock.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-18 17:55:14 +03:00
saidsurucu 2cec4dccd6 Fix user_id not defined error in bedesten search 2026-04-03 15:28:48 +03:00
saidsurucu 5c2e9cc92b Add .serena to gitignore and remove from repo 2026-04-03 02:10:18 +03:00
saidsurucu a66a3f2053 Remove auth and Fly.io deployment 2026-04-03 02:08:56 +03:00
saidsurucu a4d9e2e53d Remove mcp_auth_http_simple.py 2026-04-03 02:02:44 +03:00
saidsurucu 036e49a928 docs: Update README with Sigorta Tahkim Komisyonu (14 institutions, 22 tools) 2026-03-09 22:40:10 +03:00
saidsurucu 7f78f87508 feat: Add Sigorta Tahkim Komisyonu MCP module (3 tools)
Add Insurance Arbitration Commission integration with Tavily search
and direct PDF download for 64 quarterly journal issues (2010-2025).

Tools:
- search_sigorta_tahkim_decisions: Search via Tavily API
- get_sigorta_tahkim_document_markdown: PDF download + paginated markdown
- search_within_sigorta_tahkim_issue: Keyword search within individual
  decisions of a journal issue, with Turkish İ/I case folding support

Total tools: 25 (was 22)
2026-03-09 22:17:27 +03:00
saidsurucu d8805cb93b fix: Reject null JSON-RPC IDs per MCP spec 2025-11-25
Monkey-patch JSONRPCNotification to use extra="forbid" so that
requests with "id": null are no longer misclassified as notifications
(202 Accepted). They now correctly fail validation and return a
-32600 Invalid Request error.
2026-02-16 01:29:17 +03:00
saidsurucuandClaude Opus 4.5 28ff2e39a5 fix: Update Bedesten document source_url to mevzuat.adalet.gov.tr format
Changed source_url from API endpoint (bedesten.adalet.gov.tr/document/{id})
to user-facing URL (mevzuat.adalet.gov.tr/ictihat/{id}) for direct browser access.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-27 20:02:41 +03:00
Said Sürücü fd08637ca2 Update README.md 2026-01-15 11:00:21 +03:00
saidsurucu a5e6baeec8 fix: FastMCP 2.12+ auth import compatibility 2026-01-15 00:59:54 +03:00
saidsurucu 8818a7809a docs: Add Google Antigravity setup instructions 2025-12-27 11:05:52 +03:00
saidsurucu 12d51e3735 fix: Emsal API null safety 2025-12-26 21:07:42 +03:00
Said Sürücü efe962abf1 Update README with new application udfcevir.com
Added a new application for professional conversion from Word to UDF.
2025-12-26 14:29:07 +03:00
saidsurucu 1d73265f10 feat: ChatGPT App compliance updates 2025-12-25 17:42:22 +03:00
saidsurucu f1d3b60efb feat: Add semantic search documentation and bump version to 0.2.0
- Add OpenRouter API configuration guide for Claude Desktop, 5ire, Gemini CLI
- Document semantic search workflow (initial_keyword + query)
- Update tool count to reflect optional semantic search tool
- Bump version to 0.2.0 for semantic search feature release
v0.2.0
2025-12-13 19:51:13 +03:00
saidsurucu 93e64bc1fc docs: Improve search_bedesten_semantic parameter descriptions for LLM usage 2025-12-13 19:44:59 +03:00