{"ref":"artifact:yassinbahri-pyrfc-mcp","page":"/artifacts/yassinbahri-pyrfc-mcp","json":"/artifacts/yassinbahri-pyrfc-mcp.json","generated":"2026-10-26","drafted_with_ai":true,"entity":{"id":"yassinbahri-pyrfc-mcp","name":"pyrfc-mcp","artifact_type":"mcp-server","ecosystem":"abap","domain":"ai-and-agents","secondary_domains":["integration-and-messaging"],"origin_ring":"independent","description":{"one_line":"An MCP server for calling an SAP system's RFC-enabled function modules from an agent, built so that discovering a function does not authorise calling it: a read or a write is denied unless the function name matches an allowlist the server is configured with.","short":"MCP server calling RFC-enabled function modules behind an allowlist","what_it_solves":"Six tools sit over [PyRFC](external:pyrfc): `search_rfc_functions` finds a function by pattern or group, `get_rfc_function_interface` returns its parameters, `call_rfc_function` executes it in read or write mode, `commit_rfc_transaction` and `rollback_rfc_transaction` close what a write opens, and `read_abap_source` fetches a program's source over ADT where that is reachable and over RFC otherwise, with no transport choice handed to the caller. The policy layer is the part that is not a thin wrapper: a read or a write needs the function name to match an explicit allowlist, mutating names are denied by rule, the generic table readers are guarded at table level, and a result is rejected rather than truncated when its nested table rows or serialised bytes exceed the configured limit, with every policy decision and call outcome written to an audit log. A write returns an opaque `transaction_id` to reuse for related writes and then hand to commit or rollback, which pins the whole SAP LUW to one RFC connection, and an abandoned transaction expires and rolls back on its own. It runs as a stdio process from a local install, with connection and policy settings in a `.env` file and a `doctor` command that checks both those and the native dependencies without contacting SAP unless `--connect` is passed. A demo backend answers with synthetic RFC metadata and business records through the same discovery, validation, authorisation and limiting layers, so the tools can be exercised before any SAP prerequisite is in place.","when_not_to_use":"Real SAP calls need the proprietary [SAP NetWeaver RFC SDK](external:sap-nw-rfc-sdk) and the `pyrfc==3.3.1` release the README calls archived and yanked, on Python 3.11, so without those only the demo backend answers. Not over HTTP as it stands: credentials are read from the environment for stdio, and the README says not to expose the server over HTTP without implementing the MCP authorization specification and deployment-level rate limiting. Multi-tenant auth and RBAC beyond the one server-wide policy, rate limiting, metrics and tracing, and deployment packaging are listed as not built. The result limits protect the client and not the system, since the README states they cannot reduce work already performed inside SAP, and the MCP tool annotations that describe read and write risk are advisory metadata rather than an authorisation boundary, so the service account's `S_RFC` and table authorisations are still what decides."},"links":{"repo":"https://github.com/yassinbahri/pyrfc-mcp","homepage":"https://pypi.org/project/pyrfc-mcp/"},"identity":{"author":"Yassin Bahri","license":"MIT"},"source_available":true,"agent":{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Try it without SAP","checked":"2026-09-29"},"install":"python -m pip install pyrfc-mcp\nrfc-mcp doctor --demo --connect\nrfc-mcp --demo"},"type_properties":{"runs":{"value":["local-process"],"sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Try it without SAP","checked":"2026-09-29","quote":"python -m pip install pyrfc-mcp"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Try it without SAP","checked":"2026-09-29","quote":"Configure an MCP client with the included [.mcp.json.example](.mcp.json.example)"}]},"transports":{"value":["stdio"],"sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Security posture","checked":"2026-09-29","quote":"Stdio credentials come from the environment and are never placed in MCP tool arguments."}]},"read_only":{"value":false,"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Tools","checked":"2026-09-29","quote":"`call_rfc_function(function_name, parameters, mode=\"read\"|\"write\", transaction_id=None)`"}},"guardrails":[{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"It is deny-by-default: discovering an RFC does not authorize calling it."}},{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"Function allowlists, mutating-name deny rules, sensitive-table guards, result limits, and connection-affine transactions remain enforced at the server."}},{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Security posture","checked":"2026-09-29","quote":"Reads and writes are denied unless their function names match explicit allowlists."}},{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Security posture","checked":"2026-09-29","quote":"MCP tool annotations describe read/write risk for capable clients, but are advisory metadata—not an authorization boundary."}},{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Security posture","checked":"2026-09-29","quote":"Do not expose the server over HTTP without implementing the MCP authorization specification and deployment-level rate limiting."}},{"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Security posture","checked":"2026-09-29","quote":"they cannot reduce work already performed inside SAP"}}]},"provides":[{"capability":"capability:agent-systems-access","what_it_does":"Puts an SAP system's RFC-enabled function modules in front of an agent as tools, with finding a function and reading its interface kept apart from calling it, and a policy layer deciding which names may be called at all.","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"MCP server exposing SAP RFC-enabled function modules (BAPIs/RFCs) to AI agents through a discovery-first interface"},{"url":"https://pypi.org/project/pyrfc-mcp/","title":"pyrfc-mcp — PyPI","checked":"2026-09-29","quote":"A policy-controlled MCP server for discovering and calling SAP RFC functions"}]},{"capability":"capability:agent-code-access","what_it_does":"Reads ABAP program source out of the system for the agent through one tool, over ADT where that is reachable and over RFC otherwise.","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"automatic ABAP source reading (ADT when reachable, transparent RFC fallback otherwise"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Tools","checked":"2026-09-29","quote":"`read_abap_source(object_type, object_name, function_group=None)`"}],"facets":[{"key":"read_source","value":true,"source":{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Tools","checked":"2026-09-29","quote":"`read_abap_source(object_type, object_name, function_group=None)`"}}]},{"capability":"capability:tool-governance","what_it_does":"Decides what an agent may call before the call happens: read and write allowlists of function names, a deny rule for mutating names, a table-level guard on the generic table readers, fail-closed limits on what a result may return, and an audit log of every policy decision and call outcome.","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Scope","checked":"2026-09-29","quote":"including a deny-by-default read/write policy, a table-level guard against the generic-table-reader injection surface (`RFC_READ_TABLE` et al.), fail-closed RFC response limits, and audit logging of every policy decision and call outcome"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"It is deny-by-default: discovering an RFC does not authorize calling it."}]}],"requires":[{"ref":"external:sap-nw-rfc-sdk","requirement":"conditional","condition":"a real SAP system is called; demo mode replaces the SAP transport with a synthetic backend","for":"the native library PyRFC binds to, and the prerequisite the README sends a reader to its setup document for before any live call","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Setup","checked":"2026-09-29","quote":"Real SAP connectivity additionally requires the proprietary SAP NW RFC SDK"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Try it without SAP","checked":"2026-09-29","quote":"No SAP account, PyRFC installation, or SAP NW RFC SDK is needed for demo mode."}]},{"ref":"external:pyrfc","requirement":"conditional","condition":"a real SAP system is called; demo mode replaces the SAP transport with a synthetic backend","for":"the RFC client every live call goes through, pinned to the 3.3.1 release the README calls archived and yanked","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Setup","checked":"2026-09-29","quote":"the archived/yanked `pyrfc==3.3.1` connector"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Try it without SAP","checked":"2026-09-29","quote":"No SAP account, PyRFC installation, or SAP NW RFC SDK is needed for demo mode."}]}],"connects":[{"ref":"external:abap-platform","interface":"rfc","kind":"data","protocols":["rfc"],"direction":"outbound","style":"sync","for":"Calls remote-enabled function modules in the system and reads program source from it; a write holds the whole SAP unit of work on one RFC connection until it is committed or rolled back.","sources":[{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README","checked":"2026-09-29","quote":"MCP server exposing SAP RFC-enabled function modules (BAPIs/RFCs) to AI agents through a discovery-first interface"},{"url":"https://raw.githubusercontent.com/yassinbahri/pyrfc-mcp/main/README.md","title":"yassinbahri/pyrfc-mcp — README, Scope","checked":"2026-09-29","quote":"This pins the entire SAP LUW to one RFC connection"}]}],"maintainers":["actor:yassinbahri"],"provenance":{"discovered_via":[{"source":"source:curator"}],"first_seen":"2026-09-29"},"history":[{"date":"2026-09-29","field":"entry","to":"created","reason":"Handed over as a URL. Filed behind the ABAP door because the system it reaches is an ABAP one and the reader who points it at theirs is working on that system, which is the opposite case from [open-rfc](artifact:marianfoo-open-rfc), a client an ABAP developer would never install. Three edges: [MCP servers](capability:mcp-servers) for the tool surface over function modules, [agent access to your code](capability:agent-code-access) for `read_abap_source` alone, and [tool governance](capability:tool-governance) for the allowlists, the table guard, the result limits and the audit log, which the README states as the point of the server rather than as a footnote. [RFC connectivity](capability:rfc-connectivity) was considered and left off: the RFC client here is [PyRFC](external:pyrfc), so nobody installs this to call a function module from their own code. No flavor is stated, since the README names no ABAP release or cloud edition, and `auth` and `tool_count` are left out because the README names neither a mechanism nor a number."},{"date":"2026-10-09","field":"provides","from":"capability:mcp-servers","to":"capability:agent-systems-access","reason":"The concern it answers is reaching into an SAP system from outside, split out of MCP servers on this day; the sentence on the edge is unchanged."}],"drafted_with_ai":true,"contributors":["actor:yassinbahri"],"changed_in":[{"version":"0.1.0","date":"2026-09-04","what_changed":"Read access is denied by default and needs an explicit allowlist.","invalidates":"Earlier setups in which read calls ran without a configured allowlist.","source":{"url":"https://github.com/yassinbahri/pyrfc-mcp/blob/main/CHANGELOG.md#010---2026-09-04","title":"pyrfc-mcp changelog, 0.1.0","checked":"2026-10-19","quote":"Read access is deny-by-default and must be explicitly allowlisted."}}]},"effective_normative_relations":[],"readings":{"liveness":[{"label":"Maintenance","tier":"unknown","evidence":"no release data"},{"label":"Continuity","tier":"fair","evidence":"2 contributors"},{"label":"Repository","tier":"good","evidence":"pushed 2026-10, not archived"}],"compatibility":[{"label":"Declared for","tier":"fair","evidence":"nothing declared"},{"label":"Survived majors","tier":"unknown","evidence":"not read on ABAP: its lines run side by side"},{"label":"Maintainer's CI","tier":"good","evidence":"CI green, 2026-09-24"}],"practice":[{"label":"Tests","tier":"good","evidence":"24 test files"},{"label":"Docs","tier":"good","evidence":"docs/ with 4 pages, README 5 KB"},{"label":"Changelog","tier":"good","evidence":"CHANGELOG in the repo"}],"reach":[{"value":null,"unit":"installs/week"},{"value":1,"unit":"watching"}]},"signals":{"crawled_at":"2026-10-25","npm":"not published under this name","stars":1,"forks":0,"open_issues":10,"archived":false,"pushed_at":"2026-10-19","license_spdx":null,"org_owned":false,"default_branch":"main","created_at":"2026-08-27T08:32:31Z","tree_truncated":false,"test_files":24,"workflows":3,"other_ci":false,"readme_bytes":5581,"docs_files":4,"changelog":true,"license_file":true,"dts_files":0,"first_commit":"2026-08-26","last_commit":"2026-09-24","commits":64,"contributors":2,"ci_status":"success","ci_run_at":"2026-09-24","ci_workflow":"CI","ci_event":"push","readme_path":"README.md","readme_sha":"024162e049418dcf342b8ba3eb399e44ff4d5c0b","open_prs":7,"repo_read":"2026-10-25"},"release_notes":{"license":"MIT","quotable":true,"source":{"kind":"repo","path":"CHANGELOG.md","ref":"main","url":"https://github.com/yassinbahri/pyrfc-mcp/blob/main/CHANGELOG.md"},"format":"keep-a-changelog","releases":[{"version":"0.2.0","date":"2026-09-24","date_source":"heading","heading":"[0.2.0] - 2026-09-24","url":"https://github.com/yassinbahri/pyrfc-mcp/blob/main/CHANGELOG.md#020---2026-09-24","sections":[{"kind":"feature","heading":"Added","items":4},{"kind":"change","heading":"Changed","items":3},{"kind":"fix","heading":"Fixed","items":1}],"hash":"942fe1f76d5ccc9b"},{"version":"0.1.0","date":"2026-09-04","date_source":"heading","heading":"[0.1.0] - 2026-09-04","url":"https://github.com/yassinbahri/pyrfc-mcp/blob/main/CHANGELOG.md#010---2026-09-04","sections":[{"kind":"feature","heading":"Added","items":4},{"kind":"change","heading":"Changed","items":3},{"kind":"removal","heading":"Removed","items":1}],"hash":"584844e17485c8d1","cited_by":[{"version":"0.1.0","date":"2026-09-04"}]}],"crawled_at":"2026-10-25"},"edges":{"maintainers":[{"ref":"actor:yassinbahri","name":"Yassin Bahri","json":"/actors/yassinbahri.json"}],"contributors":[{"ref":"actor:yassinbahri","name":"Yassin Bahri","json":"/actors/yassinbahri.json"}],"explained_by":[],"alternative_to_this":[],"needed_by":[],"available_via":[],"parts":[],"add_ons":[],"answered_through_parts":[]}}